Plan: task-observer rollout across p24-infra + et-operational-platform

Status: IN PROGRESS — repo-side P1 (vendored bundle), P2 (CLAUDE.md activation block) and P3 (scripts/task-observer-bootstrap.sh) are implemented in PR #7374 and tested only as far as a cloud session can (script guards verified; no real machine has run it). Everything that needs a machine or live credentials is not done and is owned by the interactive lap2 session: see §6a. Type: Design + rollout plan Source skill: rebelytics/one-skill-to-rule-them-all — skill name task-observer, version 3.5.0, reviewed at commit da860265ae968bdc6bb13b96c2c75fcb61176b72 (2026-10-04). Licence CC BY 4.0 (attribution required — see §6 P1).

No secret values anywhere in this plan or in observations — key names only (CLAUDE.md §Safe secret handling). No step here needs a SOPS decrypt; if one appears necessary, stop and delegate to secret-manager.


1. Objective

Adopt the task-observer methodology so that both repos — p24-infra and et-operational-platform — (a) capture friction from real sessions as per-file observations, (b) review them on a cadence, and (c) deliver skill/command improvements only through the existing PR-to-main / PR-to-dev gates. One bundle, one activation contract, one review procedure; per-repo differences are limited to where skill files live and which branch the staged updates target.

Non-goals: auto-editing live skills (the skill itself forbids it — staging only); changing the priorities register; replacing autoresearch (see D1).

2. What the skill needs (facts from the source review)

  • Bundle = SKILL.md + references/ (7 files, loaded on demand) + scripts/ (new-observation.sh, migrate-log.py, validate-skill-bundle.py). SKILL.md alone runs degraded.
  • Log = a directory of one-file-per-observation under a pinned absolute workspace path ([workspace]/skill-observations/observation-log/), archive under archive/, staging under [workspace]/skill-updates/. The workspace must be one stable path per machine, never inside a checkout, a worktree or a skills-discovery directory.
  • Snippets are bash, not sh; every expansion of the path stays double-quoted. On Git Bash for Windows runs of backslashes can arrive halved — prefer forward-slash paths and the helper script.
  • Installing is not activating: needs a CLAUDE.md activation block (and ideally a SessionStart hook) and a fresh-session verification.
  • A start-up rule in a project file reaches every agent the project dispatches; workers and subagents must be explicitly exempted (they write nothing; findings go in their report).
  • Disposable workers / ephemeral checkouts → report-back mode (no log writes).

3. Repo facts this plan builds on

FactWhere
Skills live in .claude/skills/<name>/SKILL.md (p24-infra) and no .claude/skills/ dir at all in et-op — only .claude/commands/ (53 files; its CLAUDE.md documents 34) and user-level skills it lists under ~/.claude/skills; the vendored copy creates .claude/skills/task-observer/ thereboth CLAUDE.md, verified against a clone 2026-10-04
Existing meta-skill autoresearch + hook .claude/hooks/post-skill-log.sh → .claude/autoresearch/invocations.jsonl; drafts patches after 3+ recurrences, never auto-applies.claude/skills/autoresearch/SKILL.md
SessionStart / Stop / StopFailure hooks already wired to agent-session-start.sh / agent-session-end.sh.claude/settings.json
P24_WORKER_LABEL / P24_ENVIRONMENT — local/local on dev workstations, BMS4-1/bms-4, IO1/vps-i1 etc. on servers; set in server startup envdocs/agent-session-audit.md §Per-VPS setup
lap2 = Windows user Radek, repo C:\devWork\p24-infra, Git Bash; windows-dev = user konar, repo C:\code_2026\p24-infradocs/environments/lap2.md, dev-workstation.md
WSL2 on windows-dev and lap2 is also an ephemeral Docker worker host class (ADR-006)docs/environments/windows-dev.md, lap2.md §WSL2 Worker Host
et-op: skill files carry state: frontmatter; production = ask before editing; CLAUDE.md edits must be mirrored in docs/developer-work-instruction.md; CLAUDE_ENV_LAST_CHANGED must be bumped when skills changeet-op CLAUDE.md
p24-infra: all changes via PR to main; docs in docs/ mirror to p24-infra-docs; settings edits are guarded by pre-write-edit-settings-guard.shp24-infra CLAUDE.md, hooks

4. Environment matrix

EnvironmentModeWorkspace
windows-dev — Windows (Git Bash/PowerShell)fullC:/Users/konar/.claude/skill-observations
windows-dev — WSL2 interactivefull, same log as Windows/mnt/c/Users/konar/.claude/skill-observations
lap2 — Windows (Git Bash)fullC:/Users/Radek/.claude/skill-observations
lap2 — WSL2 interactivefull, same log as lap2 Windows/mnt/c/Users/Radek/.claude/skill-observations
WSL2 Docker ephemeral workers (windows-dev, lap2)report-backnone
bms-4 workers (claude-runner, claude-runner-2)report-backnone
vps-i1 agents, cloud sessions (claude.ai/code)report-backnone

Windows and WSL on one machine share one log through /mnt/c, so they are not a shard. Two machines (windows-dev, lap2) = two logs — the question handled by D3.

  • D1 — autoresearch stays. It is the mechanical, hook-driven invocation log; task-observer is the human-correction/gap layer. Reassess after the first two reviews. Alternative: retire autoresearch and let task-observer’s review subsume it.

  • D2 — One bundle, canonical copy in p24-infra at .claude/skills/task-observer/, vendored unmodified into et-op at the same path. A VENDORED.md beside it records source repo, commit SHA, version and licence; updates are a deliberate lockstep PR in both repos. No auto-update.

  • D3 — Per-machine logs, consolidated at review time. Each interactive machine keeps its own workspace; shared nothing at runtime. The weekly review runs on one machine and imports the other machine’s open entries (re-issuing ids, per the skill’s consolidation rules) via a private git repo radieu/p24-skill-observations with one directory per host. Alternative: no sync repo; review each machine separately (simpler, loses cross-machine clustering). Creating a repo is outward-facing → needs explicit user approval in Phase 0.

  • D4 — Workers never write to a log. Discriminator: P24_WORKER_LABEL != local (or unset + running under the dispatcher). Worker findings go into the existing issue callback comment under a fixed heading ### Skill observations, which the review session mines. Cloud sessions use the same report-back route (PR description section).

  • D5 — Observations never carry secret values. The activation block repeats the CLAUDE.md absolute rule and the “No SOPS decryption” clause for research agents.

  • D6 — Weekly review is automatic and claimed per week (see D8). It runs on whichever full-mode environment (windows-dev, lap2) is first active in the ISO week; staged skill updates are still applied only via PR (main in p24-infra, dev in et-op). Never unattended on workers.

  • D7 — Activation = CLAUDE.md block + additive SessionStart hook, and the install is reported “activation unverified” until a new session shows the skill invoked on its own.

  • D8 — Weekly-review claim protocol (decided by the user 2026-10-04). The weekly review is a recurring row in the priorities register. The first environment that picks it up in a given ISO week records that it took it, and records when it finished; later sessions that week see the marker and skip. This is a soft advisory lock in the style of et-op’s release lock (#1918), carried by the row’s status_detail:

    • Format: W<YYYY>-<WW> CLAIMED <host> <UTC ts> → W<YYYY>-<WW> DONE <host> <UTC ts> reviewed=<n> staged=<m> (or ABORTED <host> <UTC ts> <reason>). <host> = machine id (windows-dev, lap2), not local; define it in Phase 0 (hostname or a new P24_HOST_ID).
    • Session-start check (interactive, full-mode only): read the row. DONE for the current ISO week → skip. CLAIMED younger than 3 h with no later DONE/ABORTED → skip and name the host. Otherwise (no marker for this week, or a stale claim) → claim (priorities.py update <id> --status in_progress --status-detail "<CLAIMED …>"), run the review, then write DONE (--status open). Every exit past the claim writes ABORTED — never leave a dangling claim.
    • The review runs as a background agent so it does not block the user’s session; it follows the skill’s references/weekly-review.md (staging only, no live edits). This overrides the skill’s default “offer, don’t run” for interactive sessions — implemented in the CLAUDE.md activation block, not by editing the vendored SKILL.md.
    • Known limits (accepted, as with #1918): not atomic — two machines starting within seconds can both claim; the second claim re-reads the row before writing and aborts if a fresh claim appeared. Needs the Supabase PAT in the environment, which both dev machines have; cloud sessions and workers never run it.
    • The review also writes a one-page summary reviews/<YYYY>-W<WW>-<host>.md (in the sync repo when it exists) so the audit trail outlives the row’s single status_detail field.

6. Phases

P0 — Decisions (lap2 session, first). Answer §8, record answers in this file’s §9, then proceed. Nothing below starts before D1/D3 are decided.

P1 — Vendor the bundle (p24-infra). .claude/skills/task-observer/{SKILL.md,references/,scripts/} + VENDORED.md + LICENSE.txt + a NOTICE line crediting Eoghan Henn / rebelytics.com with link (CC BY 4.0). Run the bundle’s own scripts/validate-skill-bundle.py as a check (and in CI if cheap). Do not place a backup copy anywhere under .claude/skills/.

P2 — Activation (p24-infra). Done: CLAUDE.md §“Task Observer — session activation” (adapted from references/environments.md): full mode only on the konar/Radek profiles, report-back for everything else (resolved by the bootstrap script’s exit code, default-deny is the real gate — the first call is the bootstrap alone and the skill is loaded only on exit 0, so report-back sessions never load it), P24_WORKER_LABEL as an extra guard only (the project settings.json sets it to local), secrets rule, staging-only, switch-off steps; CLAUDE_ENV_LAST_CHANGED bumped; .gitignore un-ignores the vendored dir (the repo ignores .claude/skills/* except autoresearch). Not done (lap2): the SessionStart hook in .claude/settings.json — edits there are consent-gated by pre-write-edit-settings-guard.sh, and the auto-mode classifier may refuse third-party always-on instruction text. Add one additive hook object next to agent-session-start.sh (do not replace the file; if the guard forces a full-file edit, diff before/after and confirm every existing hook/permission survived).

P3 — Per-machine workspace bootstrap. Done (script): scripts/task-observer-bootstrap.sh [--check] — resolves the root <windows profile>/.claude (/mnt/c/Users/<name> in WSL, /c/Users/<name> in Git Bash, same directory), creates/repairs it with the skill’s idempotent “Workspace creation” command plus skill-updates/, exits 3 (report-back) on P24_WORKER_LABEL != local or no known profile, refuses a path under a skills directory, a worktree or any git checkout. Covered by scripts/tests/test_task_observer_bootstrap.py (CI): exit-code contract 0/2/3, profile resolution via a fake mount (TASK_OBSERVER_MOUNT_ROOTS, test hook), path guards, idempotent re-run, legacy-log refusal, uncreatable root. Not done (lap2 + windows-dev): run it for real on each machine, in Git Bash and WSL, and confirm both print the same directory; confirm LF line endings and that bash scripts/... works on /mnt/c without relying on the exec bit; confirm /mnt/c/Users/Radek resolves in lap2’s WSL.

P4 — et-operational-platform rollout. Same bundle at .claude/skills/task-observer/ (+ VENDORED.md, licence). Set state: development semantics explicitly (no production lock on the vendored file — updates arrive only via the lockstep PR). Add the activation block to et-op CLAUDE.md and mirror it in docs/developer-work-instruction.md; add a row to the “Installed Skills” table; bump its CLAUDE_ENV_LAST_CHANGED; also add the additive SessionStart hook to et-op’s .claude/settings.json (same guard/consent caveats as P2) and a CHANGELOG entry in et-op. et-op has no .claude/skills/ directory yet — creating it is part of this phase, and its .gitignore must not exclude it. The workspace is the same per-machine user-scope path as p24-infra (skills observed from both repos feed one log); observations about et-op slash commands use target_file: (commands are not skills). PR targets dev. Needs an et-op session/checkout — a cloud session here cannot push to it without add_repo access:"push".

P5 — Worker report-back path. (blocked on Phase 0 Q5: the P24_WORKER_LABEL audit.) Add the ### Skill observations section to the callback-comment template used by the queue workers (infra/agent-prompts/worker-*.md) and the cloud-session PR description guidance. Add the review step that mines those comments. No worker gets the log path.

P6 — Cross-machine consolidation + first review. (If D3 = sync repo) create radieu/p24-skill-observations (private), per-host directories, a two-line push/pull routine in the bootstrap script. Run the first-run backfill (Session Start step 7) over CLAUDE.md corrections and recent session notes in both repos, then the first review.

P6b — Weekly-review claim protocol (D8). Add the recurring priorities row (see §11), the claim/done/aborted logic to the activation block (session-start check → claim → background review agent → DONE), and — as an explicit step — the helper scripts/task-observer-review-claim.sh, which reads/writes the row via scripts/priorities.py with the 3 h TTL and the ISO-week id so the format is not hand-typed. priorities.py has no single-row read (only list-candidates and render) — add a get <id> subcommand (with tests) or parse render. On any failure the script follows CLAUDE.md §Error Notification Standard (Discord embed + bug issue). The review agent’s credential is inherited from the spawning session’s environment (token by NAME); it never decrypts SOPS. Role for the background agent: dev-reviewer (analysis + staging only) — confirm in Phase 0. Test with fixtures: no marker, DONE this week, fresh CLAIMED, stale CLAIMED, DONE last week.

P6a — Sequencing (from the plan review). Before P6/P6b: (1) create radieu/p24-skill-observations (user or lap2); (2) run the two scripts/priorities.py add commands in §11 — the claim protocol and the P7(c) simulation need the weekly-review row to exist; (3) register the review agent in dev_r_ai_systems + the docs/eu-ai-act-compliance.md §4 inventory (autonomous Claude-powered process, internal telemetry only — classify in Phase 0) and add a dev_r_services entry if the compliance workbook rules require it.

P7 — Verify + document. (a) Open a fresh session on each of windows-dev, lap2, and one WSL interactive session; confirm the skill was invoked unprompted and checkpoints.log gained a line. (b) Confirm a dispatcher-run worker and a cloud session did not write a log and did emit the report-back section. (c) Simulate two machines in one week: the second must skip with a message naming the first. (d) Write docs/playbooks/task-observer-operations.md (setup, review, consolidation, troubleshooting: empty scan, shard detection, missing bundle files); update docs/playbooks/ index if one exists; add the CHANGELOG.md [Unreleased] entry; run /sr.

6a. Implementation status (2026-10-04)

PhaseState
P0 decisionsD1, D3, D8 decided; §8 Q4–Q7 open
P1 vendor bundle (p24-infra)Done in PR #7374 — byte-identical to the source commit (hash manifest + CI test); validate-skill-bundle.py passes
P2 activationCLAUDE.md block + env timestamp + .gitignore done; SessionStart hook pending (lap2)
P3 bootstrapScript done + tested in cloud; real-machine runs pending
P4 et-opPending — needs a push-capable et-op session
P5 worker report-backPending — blocked on Q5
P6 / P6a / P6bPending — repo creation, priorities rows, claim helper, dev_r_ai_systems
P7 verification, playbookPending — docs/playbooks/task-observer-operations.md not written yet

Rollback / switch-off (everywhere): (1) delete CLAUDE.md §“Task Observer — session activation” in each repo (sessions stop activating on the next start); (2) remove the SessionStart hook object from each .claude/settings.json; (3) delete .claude/skills/task-observer/ and the .gitignore exception; (4) set the weekly-review priorities row to resolved. The per-machine workspace lives outside the repos and is kept (observations are history); delete it by hand only if the user wants it gone.

7. Risks

RiskMitigation
Activation block reaches workers and they write observations into ephemeral clonesD4: bootstrap default-deny (no konar/Radek profile ⇒ exit 3, skill not loaded) is the gate; P24_WORKER_LABEL is secondary because the project settings.json sets it to local; P7(b) tests it
Vendored bundle drifts from the pinned sourceMANIFEST.sha256 + scripts/tests/test_task_observer_vendored.py (CI); updates only as a lockstep PR that regenerates the manifest
P24_WORKER_LABEL not set on a host class (e.g. lap2 Docker workers)Phase 0 audit of each host’s env; default-deny: unset and under dispatcher ⇒ worker
Two stable-but-different workspaces on one machine (Windows vs WSL home)Pin to the /mnt/c/... Windows path from both; P3 verifies same inode listing
Third-party instruction text in always-on config trips the auto-mode classifierVendored + SHA-pinned; if blocked, switch permission mode and retry the same tier (documented in the skill)
Per-session cost of loading SKILL.md (≈715 lines) in every sessionAccept for interactive sessions; exempt workers; revisit after review #2
Observation bodies leak secrets or client dataD5; type: internal default when unsure; review checks bodies
Overlap/contradiction with autoresearchD1; both reviewed at end of review #2

8. Open questions for the lap2 session (Phase 0)

  1. D1: keep autoresearch alongside task-observer, or retire it?
  2. D3: create private radieu/p24-skill-observations for cross-machine sync, or review each machine separately?
  3. Which machine runs the weekly review? Decided (D8): first active full-mode machine per ISO week. Remaining: how is <host> defined (hostname vs P24_HOST_ID)?
  4. Confirm lap2 pinned workspace is C:/Users/Radek/.claude/skill-observations (and that /mnt/c/Users/Radek resolves in lap2’s WSL).
  5. Audit: what do P24_WORKER_LABEL / P24_ENVIRONMENT read on lap2 Windows, lap2 WSL, the WSL Docker worker image, windows-dev WSL, and bms-4 claude-runner-2? (Decides the D4 discriminator.)
  6. Is a Stop-hook backstop wanted in addition to the SessionStart hook (the skill ships a Node one)? Note agent-session-end.sh already runs on Stop.
  7. et-op: is a session/checkout available on lap2 for P4, and does the et-op PR go to dev as usual?

9. Phase 0 decisions log

(lap2 session: record the remaining answers to §8 here, with date.)

  • 2026-10-04 — D1 / §8 Q1 decided by the user: keep both autoresearch and task-observer. Reassess after the first two reviews (§7 overlap risk stays open).

  • 2026-10-04 — D3 / §8 Q2 decided by the user: create private radieu/p24-skill-observations. Creation from the cloud session failed (403 Resource not accessible by integration — the session’s GitHub integration cannot create repositories). Still to do: the lap2 session (or the user) creates it, e.g. gh repo create radieu/p24-skill-observations --private --description "task-observer logs, per host".

  • 2026-10-04 — weekly review decided by the user (§8 Q3 / D6 / D8): automatic, recurring priorities row; the first environment active in the ISO week claims it, records CLAIMED, then DONE; others skip.

10. Kickoff prompt for the lap2 session

Read docs/plans/plan-task-observer-rollout.md in p24-infra. First complete Phase 0: answer §8 (ask the user only where the repo cannot answer; audit the P24_* env facts yourself on this machine), record the decisions in §9. Then implement P1–P3 in p24-infra as a PR to main, then P4 in et-operational-platform as a PR to dev, then P5–P7. Never display secret values; do not run sops -d. Report back per phase.

11. Priorities registration

docs/priorities.md is generated; the row is written with the sanctioned path (needs a Supabase Management API PAT in the environment by name — not available in cloud sessions):

python scripts/priorities.py add --tier P2 \
  --item "Roll out task-observer skill in p24-infra + et-operational-platform (plan: docs/plans/plan-task-observer-rollout.md) — lap2 session: Phase 0 questions, then implement" \
  --status open \
  --status-detail "Plan written 2026-10-04; awaiting lap2 session to answer §8 and execute P1–P7" \
  --notes "Per-machine logs (windows-dev, lap2; WSL shares via /mnt/c); workers/cloud = report-back; autoresearch stays (D1); sync repo radieu/p24-skill-observations (D3)" \
  --repo radieu/p24-infra
 
# recurring weekly-review row (D8) — status_detail carries the per-week CLAIMED/DONE marker
python scripts/priorities.py add --tier P2 \
  --item "Weekly task-observer review — first active dev machine per ISO week claims it (plan §5 D8)" \
  --status open \
  --status-detail "No review recorded yet; protocol: W<YYYY>-<WW> CLAIMED|DONE|ABORTED <host> <UTC ts>" \
  --notes "Recurring. Skip if DONE this ISO week or CLAIMED <3h ago. Background agent; staging only; PR for skill changes. Starts after rollout P6b." \
  --repo radieu/p24-infra