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.mdalone runs degraded. - Log = a directory of one-file-per-observation under a pinned absolute workspace path
(
[workspace]/skill-observations/observation-log/), archive underarchive/, 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
SessionStarthook) 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
| Fact | Where |
|---|---|
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/ there | both 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 env | docs/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-infra | docs/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 change | et-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.sh | p24-infra CLAUDE.md, hooks |
4. Environment matrix
| Environment | Mode | Workspace |
|---|---|---|
| windows-dev — Windows (Git Bash/PowerShell) | full | C:/Users/konar/.claude/skill-observations |
| windows-dev — WSL2 interactive | full, same log as Windows | /mnt/c/Users/konar/.claude/skill-observations |
| lap2 — Windows (Git Bash) | full | C:/Users/Radek/.claude/skill-observations |
| lap2 — WSL2 interactive | full, same log as lap2 Windows | /mnt/c/Users/Radek/.claude/skill-observations |
| WSL2 Docker ephemeral workers (windows-dev, lap2) | report-back | none |
bms-4 workers (claude-runner, claude-runner-2) | report-back | none |
| vps-i1 agents, cloud sessions (claude.ai/code) | report-back | none |
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.
5. Design decisions (recommended defaults; Phase 0 confirms)
-
D1 —
autoresearchstays. It is the mechanical, hook-driven invocation log; task-observer is the human-correction/gap layer. Reassess after the first two reviews. Alternative: retireautoresearchand 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. AVENDORED.mdbeside 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-observationswith 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 (
mainin p24-infra,devin et-op). Never unattended on workers. -
D7 — Activation = CLAUDE.md block + additive
SessionStarthook, 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>(orABORTED <host> <UTC ts> <reason>).<host>= machine id (windows-dev,lap2), notlocal; define it in Phase 0 (hostname or a newP24_HOST_ID). - Session-start check (interactive, full-mode only): read the row.
DONEfor the current ISO week → skip.CLAIMEDyounger than 3 h with no laterDONE/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 writeDONE(--status open). Every exit past the claim writesABORTED— 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 vendoredSKILL.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 singlestatus_detailfield.
- Format:
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)
| Phase | State |
|---|---|
| P0 decisions | D1, 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 activation | CLAUDE.md block + env timestamp + .gitignore done; SessionStart hook pending (lap2) |
| P3 bootstrap | Script done + tested in cloud; real-machine runs pending |
| P4 et-op | Pending — needs a push-capable et-op session |
| P5 worker report-back | Pending — blocked on Q5 |
| P6 / P6a / P6b | Pending — repo creation, priorities rows, claim helper, dev_r_ai_systems |
| P7 verification, playbook | Pending — 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
| Risk | Mitigation |
|---|---|
| Activation block reaches workers and they write observations into ephemeral clones | D4: 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 source | MANIFEST.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 classifier | Vendored + 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 session | Accept for interactive sessions; exempt workers; revisit after review #2 |
| Observation bodies leak secrets or client data | D5; type: internal default when unsure; review checks bodies |
Overlap/contradiction with autoresearch | D1; both reviewed at end of review #2 |
8. Open questions for the lap2 session (Phase 0)
- D1: keep
autoresearchalongside task-observer, or retire it? - D3: create private
radieu/p24-skill-observationsfor cross-machine sync, or review each machine separately? Which machine runs the weekly review?Decided (D8): first active full-mode machine per ISO week. Remaining: how is<host>defined (hostname vsP24_HOST_ID)?- Confirm lap2 pinned workspace is
C:/Users/Radek/.claude/skill-observations(and that/mnt/c/Users/Radekresolves in lap2’s WSL). - Audit: what do
P24_WORKER_LABEL/P24_ENVIRONMENTread on lap2 Windows, lap2 WSL, the WSL Docker worker image, windows-dev WSL, and bms-4claude-runner-2? (Decides the D4 discriminator.) - Is a
Stop-hook backstop wanted in addition to theSessionStarthook (the skill ships a Node one)? Noteagent-session-end.shalready runs onStop. - et-op: is a session/checkout available on lap2 for P4, and does the et-op PR go to
devas 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
autoresearchand 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, thenDONE; others skip.
10. Kickoff prompt for the lap2 session
Read
docs/plans/plan-task-observer-rollout.mdin p24-infra. First complete Phase 0: answer §8 (ask the user only where the repo cannot answer; audit theP24_*env facts yourself on this machine), record the decisions in §9. Then implement P1–P3 in p24-infra as a PR tomain, then P4 in et-operational-platform as a PR todev, then P5–P7. Never display secret values; do not runsops -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