Commit Graph

62 Commits

Author SHA1 Message Date
Miguel Palhas 2022bbc881 feat(week-review): scan pi/opencode, report model, effort, cost
Scanner covered Claude Code only. It now also reads pi jsonl sessions, the
opencode sqlite store, and Codex (rollout files plus the sqlite thread index
as fallback), and records per-session model, effort level, token counts, tool
errors and cost.

Cost is reported natively by pi and opencode; Claude Code and Codex are
estimated from pricing.json and marked as such, since a subscription seat is
not billed those numbers.

New models.md output ranks (tool, model, effort) by spend with cost per human
turn and a push-back count, and SKILL.md step 4 says how to read it without
turning a regex into a verdict.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-19 21:45:48 +01:00
Miguel Palhas de37048f12 feat(pr-daemon): rev- prefix on review sessions, drop filler from slugs
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-19 21:17:12 +01:00
Miguel Palhas d231902bf4 feat(pr-daemon): name sessions after the PR, group by repo
Titles were gt-/gh-prefixed and carried the repo, which duplicates how
the sidebar is already organised. Number first so it sorts, then a slug
of the PR title.

Routing no longer looks at the title at all -- a PR title can be edited
under a running session -- and matches the worktree branch instead,
covering both the head branch and the local pull/N/head one.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-19 21:15:15 +01:00
Miguel Palhas 663a5ee235 fix(pr-daemon): watch "*" in the webhook allowlist, log drops
The webhook allowlist never matched the "*" repo pattern, so every gitea
delivery was dropped as unwatched. Each drop returns 202, which the forge
records as a successful delivery, and only accepts and signature failures
were logged -- so a delivery that arrived and was discarded looked exactly
like no delivery at all.

Gitea also flags a PR comment with is_pull rather than nesting a
pull_request link the way github does.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-19 21:10:48 +01:00
Miguel Palhas 69522ce961 fix(pr-daemon): accept gitea event and action names
Gitea sends action `synchronized` where GitHub sends `synchronize`, so
pushes to a PR branch were filtered out as noise.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-19 20:55:16 +01:00
Miguel Palhas 35b4823edc fix(pr-daemon): prompt new sessions immediately, pin TMUX_TMPDIR
A started session waited for the next tick to get its opening prompt, and
the pending flag lived in memory, so a restart in between left it sitting
empty with nothing to do.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-19 19:06:32 +01:00
Miguel Palhas bc4c057d9c fix(pr-daemon): KillMode=process in the unit
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-19 19:03:55 +01:00
Miguel Palhas b2fdcda66d fix(pr-daemon): log held hints
A hint withheld because the session is busy left no trace, which reads
identical to no event at all.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-19 19:02:38 +01:00
Miguel Palhas f189abd4ee fix(pr-daemon): match worktrees, accept bot identity, log rejects
Three bugs the first live run surfaced:

aoe reports `worktree.main_repo_path` with a trailing slash, so the
session lookup never matched and the daemon created a second session for
a PR that already had one.

The gitea token belongs to a separate bot account, so PRs opened by
agents looked like someone else's work and got `review-pr` instead of
`land`. `self` now takes a list of logins per forge.

A webhook whose signature fails logged nothing, which makes a mismatched
secret indistinguishable from no deliveries at all.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-19 19:00:13 +01:00
Miguel Palhas 787f133fdc feat: PR daemon + reviewer/author skill split
One systemd daemon watches GitHub and Gitea and routes each PR to an aoe
session: `land` for PRs you authored, `review-pr` for everyone else's.
It reads metadata only and sends a single inert hint line, so untrusted
PR text never passes through the thing that types into agent prompts.

Routing is derived from `aoe list --json --all` by worktree branch, so
no claim files and no daemon database. Dedupe stays in the session via
`pr-<N>-seen`, which makes hints idempotent and a swallowed send
self-healing.

`land` loses its watcher machinery to the daemon and keeps the policy
and per-event handlers; `pr-common` holds what both skills share.

Review sessions run non-yolo without trusted hooks and never run the
branch's code.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-19 18:51:43 +01:00
Miguel Palhas 6f05756870 docs: document pi and opencode coverage 2026-08-19 15:13:51 +01:00
Miguel Palhas 6f84c63a19 feat: cover pi and opencode in link.sh
Generated (concatenated) AGENTS.md for both tools, marked so re-runs
overwrite safely; MACHINE=<name> picks the machine profile. Commands
link into ~/.config/opencode/commands alongside ~/.claude/commands.
2026-08-19 15:13:51 +01:00
Miguel Palhas c10761b1eb feat: cover pi and opencode in the home-manager module
They have no @file imports, so the module concatenates the shared
claude-md fragments into one AGENTS.md per tool (.pi/agent/ and
.config/opencode/), and links commands/ into opencode's commands dir.
Skills need nothing: pi reads ~/.agents/skills and opencode auto-loads
both skill roots, all already linked.
2026-08-19 15:13:51 +01:00
Miguel Palhas cc78bcef9c fix(merge): drop worktree cleanup step
The aoe-ownership check and its warning were noise on every merge; cleanup is the user's call.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 14:27:50 +01:00
Miguel Palhas c77171ce2c docs: drop dead crit CLI references, trim rev section
crit CLI and crit-watch.sh don't exist on this machine; rev covers
code-diff reviews entirely now.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-17 14:39:16 +01:00
naps62 7cb03f8796 feat: ship the remaining hooks and aoe-register-remote
settings.json references git-autoupdate, tmux-attention, tmux-reset and
scripts/aoe-register-remote.py, but they only existed as untracked files
on one machine, so hooks failed everywhere else.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-17 08:56:44 +00:00
naps62 d7c62c8ce3 feat: split machine-specific section out of CLAUDE.md
The entry file assumed passwordless root and LAN-exposed dev servers,
which is only true on yolo. It now @imports ~/.claude/machine.md, linked
from claude-md/machines/<name>.md via programs.agentSkills.machine.
Defaults to the conservative profile.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-17 08:38:01 +00:00
naps62 ef1b00c573 fix(merge): pick forge, leave worktree to aoe
The command hardcoded `gh pr merge`, which fails on the Gitea repos, and
deleted the worktree that Agent of Empires owns — stranding the session
and removing the directory it runs in.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-16 15:32:41 +00:00
naps62 533f97bf1e Merge branch 'hourlogs': measured hours per project per day
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 22:11:10 +00:00
naps62 5792d6454b docs: tighten hourlog, add the confirmed-entry check
Scan and report had grown into two sections saying the same thing, and
step 4 repeated step 1's "show the table". Down to four steps.

Adds what nearly went wrong on the first real run: a day already
confirmed weeks ago looks identical to a planned one in a bulk approval,
and overwriting it needs its own yes. Also records the 15-minute
rounding the app enforces, and the ${VAR:-x} expansion that prints a
token instead of hiding it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 22:11:06 +00:00
naps62 b485cee634 feat: split overlapping minutes between projects
Five minutes with two projects open was counted as five for each, so
Wednesday's columns summed to 18h against 13h10 of wall clock and no
column said which number to trust.

Each slot's minutes are now divided evenly among the projects live in
it, largest remainder over whole minutes, so the columns add up to the
total exactly. That ratio is what a submission scales the user's stated
day length by.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 22:05:13 +00:00
naps62 439d3601b4 feat: report measured time, drop the nominal-day fit
Splitting a fixed 8h day by share turned 160 minutes of Friday morning
into "7h Tesser". The number looked measured and was not, and no column
in the table said which.

Cells now carry the time each project was actually active. The total
column is wall-clock presence — the union of active slots — so it reads
lower than the row sum when sessions overlapped. Measured time is a
floor; the skill says so and leaves adding the rest to the user.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 20:33:34 +00:00
naps62 f0c301b3a3 docs: hourlog table goes in the reply unfenced
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 20:10:03 +00:00
naps62 b453e72d42 Revert "feat: draw the grid by default, --markdown to opt out"
The drawn grid was solving the wrong problem: the script output was
already right, and fencing it in chat is what turned a rendered table
into raw dashes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 19:52:30 +00:00
naps62 bf1dc76125 feat: draw the grid by default, --markdown to opt out
A markdown table carries no borders of its own; whether any get drawn is
up to the renderer, and terminal renderers mostly draw none. Emitting the
grid directly makes the output look the same everywhere it lands.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 19:51:28 +00:00
naps62 ea9c3acecf feat: emit the day report as a markdown table
Padded pipes, so it reads as a grid in the terminal and renders as a
real table when pasted anywhere else. Each cell carries hours, share and
active minutes; a flags column carries what needs judgement.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 19:26:06 +00:00
naps62 658b9850bb style: rule off the report, count only sessions in range
The session count came from the mtime prefilter, so an old date range
reported every file on disk as if it had contributed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 18:42:15 +00:00
naps62 39d88899af refactor: back to per-day blocks, add a totals line
The matrix table dropped the evidence — share, active minutes, hour
range, and the outside-working-hours flags — which are what make a
proposed number checkable rather than asserted.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 18:40:44 +00:00
naps62 cd63a4c18e refactor: hourlog prints a day-by-project table
One row per day, one column per project, hours in the cell. The per-day
blocks repeated the project name on every line and buried the totals.

Share, active minutes, hour ranges, and the outside-working-hours flags
move to --json, which is where the skill reads them anyway.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 18:38:45 +00:00
naps62 95e98a1e77 refactor: hourlog reports whole days, timer to 18:00
Half-days forced every result into a 4h bucket. Days with hours split by
share give the same answer at finer granularity and drop a concept.

Session minutes are now stated as a floor on real work, not a measure:
the day's length comes from the calendar and only the split between
projects comes from the sessions. Meetings and review leave no
transcript, so a thin day is still a full day.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 18:36:34 +00:00
naps62 e4ffd5d93d feat: hourlog skill + Friday timer
Turns Claude Code and Codex session activity into a half-day-per-project
proposal, reconciles it against the timesheet API, and submits only what
the user approves in-session.

Activity is measured in 5-minute active slots, deduplicated per project,
not message counts — otherwise one overnight autonomous run outweighs a
real morning's work.

The path-to-project mapping and the API credentials stay in
~/.config/hourlog/ and ~/.env.claude. This repo is public.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 17:35:24 +00:00
naps62 a0b42c9210 feat: land requests a Copilot review on GitHub PRs 2026-08-12 08:19:13 +00:00
naps62 19863adc15 docs: rev watcher is silent plumbing
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-12 06:14:40 +00:00
naps62 984616f5c4 fix: rev fallback asks for multi-line markdown reply bodies
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-11 20:15:40 +00:00
naps62 19bd110188 docs: name the public rev URL in the fallback
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-04 06:05:34 +00:00
naps62 1efa691b04 docs: route code reviews to rev, scope crit to plans/live/HTML
Rev hooks are installed globally; entry files describe the injected flow
plus a manual fallback (codex has no hooks). Crit skill redirects code
diffs to rev.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-03 10:12:00 +00:00
naps62 cb525048a4 docs: prefer agent-browser CLI over claude-in-chrome
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K4F9xsCrdJQXNxNZJiKpYq
2026-08-03 06:24:05 +00:00
naps62 5e95a7337f feat(week-review): spawn weekly via systemd timer
Fridays 17:00 Europe/Lisbon, pinned in the unit because the machine
clock is UTC. Creates an Agent of Empires session in a fresh
week-review/<ISO week> worktree, sends it /week-review, notifies ntfy.

Interactive, not `claude -p`: the skill asks which carry-over issues to
take and what to apply, so an unattended run would stall or decide on
its own. link.sh links the units but does not enable them, since
enabling on every machine spawns one session per box for the same week.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SC9zwjErud3jfeYVEkf2Zd
2026-08-01 15:51:34 +00:00
naps62 bdeded310a feat(week-review): filter carry-over on the weekly-review label
Reading every open issue would pull in unrelated work once the repo has
any. Newly filed issues must carry the label or the next run cannot see
them.
2026-08-01 15:28:45 +00:00
naps62 f6b58e8849 feat: add the week-review skill
Codifies the session-review process: read open issues for carry-over,
scan transcripts, rank by how often the same correction repeated, check
the current model docs before recommending, then apply or file.

scripts/scan-sessions.py enumerates top-level sessions in a window,
drops subagent transcripts, and flags swarm runs so a single 577-session
security scan does not read as 40% of the week's work.
2026-08-01 15:15:14 +00:00
naps62 ad4d14e078 docs: README still described the reverted AGENTS.md design 2026-08-01 15:02:47 +00:00
naps62 60f39cdcbb feat: track both entry files in the repo
~/.claude/CLAUDE.md was in no git repo despite heavy editing, and
~/.codex/AGENTS.md was a hand-synced duplicate of it. Both now live in
entry/ and import the shared fragments; RTK.md moves to claude-md/ so
Codex stops carrying its own copy.

Claude's imports are ~/-anchored so they resolve through the symlink.

Also drops kt from the comment rule scope.
2026-08-01 15:02:28 +00:00
naps62 9023ed3ef9 chore: update vendored skills and record provenance
humanizer 2.2.0 -> 2.9.1 (blader/humanizer, MIT): adds a Voice
Calibration section and a passive-voice pattern, reworks negative
parallelisms and em dashes. Version moved to metadata.version upstream.

impeccable 3.6.0 -> 4.0.4 (pbakaus/impeccable, Apache-2.0): the repo
tags the skill and the npm CLI separately, so 3.6.0 was a real release
and npm's 3.5.0 was never the comparison. Adds native-platform reference
briefs.

Each now carries an UPSTREAM file; bin/check-vendored.sh reports drift.
2026-08-01 14:25:26 +00:00
naps62 2f7f512cec fix: exempt doc comments from the code-comment budget
Rustdoc, JSDoc, NatSpec and docstrings document a surface for callers and
are read by tooling — NatSpec ends up in contract metadata. The rule read
as an instruction to delete them, and the linter blocked a legitimate
rustdoc block.

Also: plain block comment bodies were never linted (no per-line marker),
and a literal double-star in a code span was flagged as bold.

Merges the landmine and MUST categories, which said the same thing.
2026-08-01 14:16:48 +00:00
naps62 aacbdc2c43 chore: drop c and h from the comment rule scope 2026-08-01 14:12:43 +00:00
naps62 652b5abceb chore: drop unused languages from the comment rule scope
scala, java, cc, cpp, hpp, swift, php, cs.
2026-08-01 14:12:01 +00:00
naps62 b8d442386b feat: scope the comment rule to yaml, yml, and toml too
Adds them to both the paths glob and the linter's extension set, which
had also drifted apart on scala.
2026-08-01 14:11:08 +00:00
naps62 ccfb5192f8 refactor: both tools import the same fragments; scope code comments by path
Codex reads ~/.codex/AGENTS.md, not ~/.agents/AGENTS.md, so the file
generated there last commit was inert. Both tools support @path imports,
which removes the generate-and-drift step entirely.

code-comments.md moves to ~/.claude/rules/ with paths frontmatter, so its
24 lines load only when a source file is read.
2026-08-01 14:08:44 +00:00
naps62 36372f85b2 feat: split security and autonomy into operating.md
Nine bullets to six. Cut what the harness now ships by default: the
scope-discipline bullet, "create/modify files freely" (subsumed), and
the standalone refuse-dangerous-tasks bullet (restated the injection
rule with examples, now merged into it).

Adds progress-claim grounding for long unattended runs, per the Fable 5
guide. Codex gets both fragments now — link.sh concatenates them into
~/.agents/AGENTS.md, since Codex has no @import.
2026-08-01 13:09:36 +00:00
naps62 e449d705c3 docs: use a generic workspace name in the linearMcp examples 2026-08-01 13:07:57 +00:00