Commit Graph
8 Commits
Author SHA1 Message Date
notplantsandClaude 300e69d3b3 refactor(secrets): consumers read the store; drop materialized copies
Materializing wrote a second plaintext file per secret, which is the problem the store
was meant to solve: two files drift, and the copy is what ends up committed or grepped.

- tangled_pr / tangled_pr_edit / tangled_repo now read tangled.cookie from the store.
  engine/.tangled-session is deleted; --cookie-file remains as a legacy escape hatch.
- materialize() is replaced by run-time injection that leaves nothing at rest:
    exec-env <group> -- cmd      group as env vars (use this instead of a systemd
                                 EnvironmentFile — same effect, no plaintext on disk)
    with-file <key> -- cmd {}    0600 file in a private tmpdir, removed when cmd exits,
                                 for consumers that insist on a path (ssh -i, a TLS key)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-01 16:58:26 +00:00
notplantsandClaude 6c56c1953e refactor(secrets): store lives at /secrets, not /srv/secrets
/srv is the projects tree — agents grep, find and `ls -R` it constantly, so a store
under it turns up in ordinary searches and risks being read (or pasted) by accident.
/secrets sits outside that blast radius: nothing routinely walks it, and it is still
0700 loops, still not a repo, still ciphertext at rest.

Override with AO_SECRETS_STORE if a host puts it elsewhere.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-01 16:54:03 +00:00
notplantsandClaude 7605efe624 feat(secrets): one sops+age store for the host, documented for every project
Credentials were scattered in plaintext: a gitea password baked into six git remote
URLs (`git remote -v` prints those), API keys in .env files, an incus client key at
0644. Anything living in a repo is one `git add -A` from being pushed.

So: ONE encrypted file outside every git tree, and a helper each project uses.

  /srv/secrets/store.yaml       sops+age ciphertext, 0600, not a repo, no remote
  ~/.config/sops/age/keys.txt   the only plaintext secret on disk, 0600

secrets.py is stdlib + the sops binary: get("group.key"), get_group("group"), and
materialize() for consumers that must read a fixed path (systemd EnvironmentFile,
ssh IdentityFile, nix authKeyFile) — those keep their file, but the store is the
source of truth, so a materialized file is never hand-edited.

`list` prints names only, never values, so it is safe in a transcript.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-01 16:51:36 +00:00
notplants 98d198baa9 feat(handoff): claim_pings/review_pings accept a list — ping every reviewer
Multi-reviewer setups (e.g. a correctness + a readability adversary) can now have
the watchdog ping ALL reviewers on a claim, each in its own session with its own
submit key. A bare string still works (single agent). _ping_agents() helper.
2026-06-22 00:24:41 +00:00
notplants 781db071dd docs(readme): add Examples section (Builder/Adversary variants, snakepit) + benchmark note 2026-06-16 02:35:40 +00:00
notplantsandClaude Opus 4.8 924874aafa feat: optional log_tokens — per-phase token + time accounting
When [watchdog].log_tokens (or [loop].log_tokens) is true, the watchdog records
for each phase how many tokens each agent used (and the total) and how long the
phase took, appended to <log_dir>/token-log.jsonl. Tokens are summed from each
agent's session transcript, attributed by working dir. View with `agents.py
tokens`. Baseline snapshot at phase start + delta at phase advance/complete;
robust across watchdog restarts. Validated: the transcript sum matches an
independent external collector exactly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 21:48:17 +00:00
autonomic-botandClaude Opus 4.8 cdcece9a9a test: add tests/ — unit suite + isolated live claude/opencode smokes + runner
Unit tests (no agents/tmux): config load + defaults merge, kickoff-template
assembly, phase machine (advance/idempotent-complete/append-resumes), limit
reset-banner parsing, WAITING-UNTIL/stall parsing, claude+opencode activity
detectors. Live smokes bring a throwaway project up THROUGH agents.py on each
real backend in an isolated sandbox (unique prefix, opencode on a non-4096
port), verify attach + status + down, and clean up. tests/run.sh runs unit
always + smokes when backends present; README documents it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 18:55:34 +00:00
autonomic-botandClaude Opus 4.8 289ef07df4 feat: agent-orchestrator v0.1.0 — generic multi-agent harness
Extracted and generalized from a project-specific agent launch engine. No project
specifics remain in code: paths, the loop kickoff preamble, handoff conventions, and the
on-complete hook are all config/template driven; session_prefix + log_dir are required.

- agents.py: driver + watchdog (data-driven backends via prompt_delivery arg|ping|exec;
  required session_prefix/log_dir; project-rooted path resolution; configurable kickoff
  template, handoff patterns, on_complete task; tmux-safe; selftest + init verbs)
- agent-log.py: config-driven claude transcript renderer
- agents.example.toml: self-contained 2-agent example (dependency-free demo backend)
- prompts/: generic builder/adversary/kickoff templates
- smoke.sh: isolated up+down sandbox proof that cleans up after itself
- flake.nix/.lock: devShell (python311 + tmux + git)
- README.md: schema + verbs + AI-PO usage + nix

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 18:39:00 +00:00