~bigbes/agents-dev · events

cjjrehb25j43fj1bo2gf5t56uubci76i · 131 rows

idissue_idevent_typeactorold_valuenew_valuecommentcreated_at
019f5a77-eda7-7288-aa1a-d7bf1cffad00ah-xuc.12claimedEugene Blikh{"id":"ah-xuc.12","title":"docs: sync SPEC with Stage 2 behavior","description":"SPEC.md gains normative Stage 2 sections mirroring what landed, in the established style (invariants and failure modes, not narrative): domain deltas (stalled outcome, canonical buckets as a superset of states, Run.Timeout), ports deltas (Labels, Skills, Publish), store v2 migration, vikunja labels, runner skills plus publish (never force-push), reconciler claim spec resolution + Triage bounce + parked buckets + per-run timeout + watchdog + notification ordering, httpapi webhook endpoint (HMAC, disabled when unset), config reference with the full new example, security notes (webhook secret, TG token redaction, srht push scope), roadmap section 14 marks Stage 2 delivered. Cross-check config.example.yaml for drift. AGENTS.md and CLAUDE.md only if conventions changed (mirror both if so — independent files).","acceptance_criteria":"Each new SPEC section spot-checked against the shipped code; no contradiction with Stage 1 sections; the research-v3 supersede note stays accurate","status":"open","priority":2,"issue_type":"task","owner":"bigbes@gmail.com","created_at":"2026-07-13T05:16:35Z","created_by":"Eugene Blikh","updated_at":"2026-07-13T05:16:35Z"}{"assignee":"Eugene Blikh","status":"in_progress"}NULL2026-07-13T10:53:56Z
019f5a86-c89e-78d5-9d45-9fa111bd917fah-6u0createdEugene BlikhNULL2026-07-13T11:10:10Z
019f5aa0-3d65-756e-91b2-774951842177ah-wkacreatedEugene BlikhNULL2026-07-13T11:37:58Z
019f5aa0-82d6-775e-bb66-67329b52a4beah-xuc.11closedEugene Blikh8e29554; reviewer merge-ready with zero findings — stub honesty, hermeticity, timing discipline, full-argv equality all verified; 3-run flake probe: all six Stage 2 flows green in all runs (the one flake found is pre-existing Stage 1, filed as ah-wka)NULL2026-07-13T11:38:16Z
019f5aa0-85b0-7ed4-a1ad-3695bf4f9c33ah-xuc.12closedEugene Blikhe13b65c + b48849f (two wording nits); accuracy reviewer merge-ready — every behavioral claim verified against code; SPEC section-12 example validates through ahub validate-config; pre-existing RunStatus.MetaAttempt drift filed as ah-6u0NULL2026-07-13T11:38:17Z
019f5aa0-88ab-7036-9543-c212c67ea38dah-xucclosedEugene BlikhStage 2 delivered: 21 commits b3ee57d..HEAD (webhook HMAC poke, Task Spec frontmatter + type-label presets + Triage bounce, parked buckets Triage/Blocked/Question, per-run timeout with store v2, stall watchdog, Telegram notifier via HTTPS_PROXY, review-branch publish to srht remotes with bounded push, e2e flows, SPEC synced to Stages 1-2). Every wave gated by hostile review + empirical validation; final epic-wide gate 11/11. Runtime prerequisites (board columns, webhook target, srht repos, TG bot) remain in ah-k23.NULL2026-07-13T11:38:18Z
019f5aa7-e2b9-7290-a42a-74e32834a4cbah-wkaclaimedEugene Blikh{"id":"ah-wka","title":"runner: Status crash-inference race misclassifies a finished run (e2e flake)","description":"Found by the Stage 2 closing review (3-run e2e probe, 1 failure in 3): TestE2E (Stage 1) tasks 101/102 finalized as outcome=crashed / exit_code=-1 even though the daemon log shows the correct run-exit report received (exit_code 0/1). Root cause per static read: PiZellij.Status (internal/runner/runner.go, crash-inference fallback around lines 210-215) infers Completed/OutcomeCrashed whenever it observes neither exit.json for the attempt nor a live zellij session — a visibility window between ahub-run writing exit.json (atomic rename) and the session-liveness check observing the dying session. The e2e stub session dies immediately at child exit, making the window wide; real zellij keep-pane narrows but does not provably close it (kill-session paths, crashes). Pre-existing Stage 1 behavior, NOT introduced by the Stage 2 commits (all six Stage 2 flows were green in all three runs).\n\nDirection to evaluate: make the crash inference sticky-read-ordered — check exit.json AGAIN after observing the session dead (dead session THEN a fresh exit.json stat), or require N consecutive dead observations before inferring a crash, or have Status treat session-dead-without-exit.json as the neither-state (no evidence) for one grace tick instead of hard Completed/crashed. Any fix must keep the SPEC section 9 three-state contract and the section 10 adopt semantics intact.","acceptance_criteria":"The race window is closed or bounded (re-check ordering or grace tick); a regression test reproduces the old misclassification deterministically (stub with delayed exit.json visibility); 10 consecutive full e2e runs green","status":"open","priority":2,"issue_type":"bug","owner":"bigbes@gmail.com","created_at":"2026-07-13T08:37:59Z","created_by":"Eugene Blikh","updated_at":"2026-07-13T08:37:59Z"}{"assignee":"Eugene Blikh","status":"in_progress"}NULL2026-07-13T11:46:19Z
019f5aa7-e475-700b-9d01-31a057b031eeah-6u0claimedEugene Blikh{"id":"ah-6u0","title":"docs: SPEC section 6 RunStatus struct omits MetaAttempt","description":"Pre-existing Stage 1 drift found during the Stage 2 SPEC sync (ah-xuc.12): the RunStatus struct listing in SPEC section 6 lacks the MetaAttempt field even though section 9 prose relies on RunStatus.MetaAttempt (the attempt recorded in .task/meta.json, 0 when absent). Make the section 6 struct field-complete to match internal/ports/ports.go.","status":"open","priority":4,"issue_type":"task","owner":"bigbes@gmail.com","created_at":"2026-07-13T08:10:10Z","created_by":"Eugene Blikh","updated_at":"2026-07-13T08:10:10Z"}{"assignee":"Eugene Blikh","status":"in_progress"}NULL2026-07-13T11:46:20Z
019f5acc-e475-7bbf-9862-ee91860a2752ah-wkaclosedEugene Blikh2783d16 + 56f84bf (SPEC section 9 sync): crash inference now confirm-after-grace (re-stat + 5s window returning the neither state). Regression test falsified against old logic; 15/15 independent e2e runs green vs ~1-in-3 pre-fix; -race clean; reviewer merge-ready with the adopt corner independently confirmed unreachableNULL2026-07-13T12:26:45Z
019f5acc-e76b-7c9a-bfb2-8b08a3c05f17ah-6u0closedEugene Blikh279b733: MetaAttempt added to SPEC section 6 RunStatus listing, alignment verified against gofmt; accuracy-reviewed in the follow-up gateNULL2026-07-13T12:26:45Z
019f5add-4ef9-76b2-afcb-8c93b6a34284ah-dddcreatedEugene BlikhNULL2026-07-13T12:44:40Z
019f5add-8608-7ca6-8e41-df42dd9c42a1ah-dddclaimedEugene Blikh{"id":"ah-ddd","title":"ntfy: notifier for ntfy-compatible endpoints (Prism)","description":"The operator runs Prism (phoebe-lab/prism), an ntfy-compatible notification gateway at https://prism.bigb.es/{topic} that delivers to Telegram and owns the TG proxy egress itself (patched Telego + lab singbox). Publishing to it is a plain lab-local HTTPS POST — no HTTPS_PROXY handling needed in the daemon (prism.bigb.es is inside the NO_PROXY zone). This replaces the operational need for the direct Telegram path; internal/telegram stays as an alternative.\n\nNew package internal/ntfy implementing ports.Notifier: POST the configured topic URL with Authorization: Bearer \u003ctoken\u003e, Content-Type application/json, body {\"message\": \u003ctext\u003e} (title omitted — ntfy treats it as optional; per the Prism README the JSON publish shape is {\"title\",\"message\"}). 10s client timeout, bounded response read, non-2xx = error with a short body prefix, bearer token never in logs or error strings (redact like internal/telegram does), no retries (Notify is best-effort by contract).\n\nConfig: ntfy block {url, token} — present when either is set, then both required; url must parse as http(s). Configuring BOTH ntfy and telegram is a config error (exactly one notifier; explicit over precedence). config.example.yaml gains a commented block pointing at a Prism topic URL with ${PRISM_API_KEY}.\n\ncmd/agenthubd: notifier selection becomes ntfy | telegram | slog no-op (config validation guarantees not-both); construction error fatal at startup like telegram.\n\nDocs: SPEC section 4 layout (internal/ntfy), section 6 Notifier comment, section 12 config example + validation rules, section 15 security note (bearer key via env ref, token redaction).","acceptance_criteria":"go test ./internal/ntfy/... ./internal/config/... ./cmd/... green with -race on ntfy; httptest covers success, non-2xx, token redaction, context cancellation; config table tests cover both-or-neither, bad url, both-notifiers-configured error; wiring test asserts ntfy selected when configured; full go test ./... and -tags e2e green; SPEC updated in the same style as the Stage 2 sync","status":"open","priority":2,"issue_type":"feature","owner":"bigbes@gmail.com","created_at":"2026-07-13T09:44:41Z","created_by":"Eugene Blikh","updated_at":"2026-07-13T09:44:41Z"}{"assignee":"Eugene Blikh","status":"in_progress"}NULL2026-07-13T12:44:55Z
019f5afe-3104-7829-bd5b-a184b6ec55f2ah-dddclosedEugene Blikh378216d+6734986+4c3c350+5438f7c + review fix (proxy wording, trimmed presence checks); reviewer merge-ready (redirect bearer-strip verified against stdlib, no token leakage); validator 11/11 incl. live wire probe matching the Prism publish shape exactlyNULL2026-07-13T13:20:35Z
019f7082-c1b4-7157-ae07-dec21d7cbc28ah-gs7createdEugene BlikhNULL2026-07-17T17:37:25Z
019f7082-c4b1-717e-9fce-0f0b1ef05c92ah-9r4createdEugene BlikhNULL2026-07-17T17:37:26Z
019f7082-c6d6-7cc9-b26b-e18925706b63ah-166createdEugene BlikhNULL2026-07-17T17:37:26Z
019f7083-5130-7a31-9ba6-6edbe691d9f7ah-0ge.1createdEugene BlikhNULL2026-07-17T17:38:02Z
019f7083-5495-7c7b-970f-1c7fe985f283ah-0ge.2createdEugene BlikhNULL2026-07-17T17:38:02Z
019f7083-5885-7e92-a147-d910eb244507ah-0ge.3createdEugene BlikhNULL2026-07-17T17:38:03Z
019f70ba-faab-75e3-8d62-c8c196b6c5b0ah-gs7updatedEugene Blikh{"id":"ah-gs7","title":"Ultrapack designer/validator roles via config + skills (human-scheduled)","description":"Ultrapack (github.com/bigbes/ultrapack) is an OpenCode pack, but its value is the skills (udesign/uplan/uexecute/uverify/ureview), and pi implements the Agent Skills standard — so the skills load unmodified via --skill with no porting. Stage 2 already delivers --skill materialization, task_types and per-task frontmatter roles, so multi-role work needs ZERO daemon code today: add designer/validator roles to config pointing at ultrapack skill packages under skills_dir, and let a human drag cards between them. State carries between runs in docs/tasks/\u003cslug\u003e.md on the task branch. Do this BEFORE automating the handoff (ah-0ge slice): it validates whether the roles are actually good while the orchestration is still free.\nUltrapack agents/ do NOT get ported — see the delegation-loop beads; agents become roles, not subagents.","design":"Roles are {model, prompt} today (internal/config/config.go:72). Fork ultrapack skills into skills_dir packages; rewrite @implementer/@explorer/@reviewer subagent references (uplan/SKILL.md:126-128, uexecute/SKILL.md:37, handsoff/SKILL.md:35) out of the skill bodies — pi has no @-mention dispatch. Designer role MUST use ultrapack's handsoff skill: udesign/SKILL.md says 'Nothing is planned or written until the user approves', which deadlocks a board-driven run until the watchdog kills it as stalled.","acceptance_criteria":"A task labeled for the designer role produces a docs/tasks/\u003cslug\u003e.md with a Design section and lands In Review without stalling; dragging it to Ready under the validator role produces a review against that same file on the same branch.","status":"open","priority":2,"issue_type":"feature","owner":"bigbes@gmail.com","created_at":"2026-07-17T14:37:25Z","created_by":"Eugene Blikh","updated_at":"2026-07-17T14:37:25Z"}{"notes":"VERIFIED 2026-07-17 on pi 0.73.1: ultrapack skills load unmodified via --skill. Clean test (neutral empty cwd, tools on): --no-skills alone -\u003e catalog NONE; --no-skills --skill skills/udesign --skill skills/uplan -\u003e catalog is EXACTLY {udesign, uplan}. Determinism property (SPEC §9: explicit --skill under --no-skills = intended set only) holds in practice. Probe gotchas for reruns: (1) run from a dir with no skills/ folder or the model just ls-es it and reports dir names; (2) do NOT use --no-tools — pi exposes skills THROUGH a tool, so --no-tools hides even loaded skills."}NULL2026-07-17T18:38:49Z
019f70ba-fcfe-79cf-89e7-dde68993b3b5ah-166updatedEugene Blikh{"id":"ah-166","title":"pi version drift: SPEC pins 0.70.2, installed is 0.73.1","description":"SPEC §9 says 'Verified against zellij 0.44.3 and pi 0.70.2' and internal/runner/commands.go repeats the pin in its header comment, but the installed pi is 0.73.1 (@mariozechner/pi-coding-agent). Nothing is known to be broken — but every argv note in commands.go ('pi 0.70.2 still loads a path given as --skill even under --no-skills', 'There is no --name flag') is an empirical claim against a version that is no longer the one running. Re-verify the flag behaviours on 0.73.1 and update the pins, or pin the installed version deliberately.","status":"open","priority":3,"issue_type":"task","owner":"bigbes@gmail.com","created_at":"2026-07-17T14:37:27Z","created_by":"Eugene Blikh","updated_at":"2026-07-17T14:37:27Z"}{"notes":"Partial data point 2026-07-17: on installed pi 0.73.1, --skill paths STILL load under --no-skills (verified via catalog probe), so that SPEC §9 argv note survives the 0.70.2-\u003e0.73.1 bump. Full flag re-verification (--no-extensions with explicit -e, --mode json event shape, --name absence) still pending."}NULL2026-07-17T18:38:50Z
019f70c3-af18-7dfa-bb2d-1b3c51f1612eah-166closedEugene BlikhRe-verified on pi 0.73.1: no runner-relevant drift. --skill loads under --no-skills; --mode json session-id line and message_end usage.cost.total shape unchanged (confirmed with opencode/claude-haiku-4-5; deepseek reports empty usage as a provider quirk, and the user-echo message_end always had empty usage); no --name flag; -ne keeps explicit -e. Pins annotated in commands.go:8 and SPEC §369. zellij NOT re-checked.NULL2026-07-17T18:48:20Z
019f70c4-9923-7a25-898a-b4ee62bb18b8ah-9r4updatedEugene Blikh{"id":"ah-9r4","title":"DECISION: worktree/branch topology for agent-created child tasks","description":"Blocks the delegation loop. Parent X owns worktree \u003cwork_root\u003e/\u003cslug\u003e/task-X on branch agent/task-X. Where does child Y work? git refuses to check the same branch out into two worktrees, so Y cannot enter X's. Branching Y off the default branch means a later merge into X's divergent branch; branching Y off agent/task-X breaks the review/publish path, because gitLogOneline/gitDiffStat (internal/runner/commands.go) compute \u003cdefault\u003e..HEAD against the repo default branch and would report all of X's work as Y's diff.\nProposed split by whether the role writes code: ADVISORY roles (research/review/design — return text, touch no code) get a detached-HEAD worktree at X's tip. git permits many worktrees on the same COMMIT, just not the same BRANCH, so Y reads X's WIP with no collision and no merge. Only WRITER roles need real branches and a merge story — and the advisory-only subset may cover the useful cases, deferring the writer problem entirely.\nVerify the detached-HEAD claim against the pinned git before building on it.","acceptance_criteria":"A written decision recording: which roles are advisory vs writer, how each child's worktree base is chosen, and what the diffstat base is for a child (if writer roles are in scope at all).","status":"open","priority":2,"issue_type":"task","owner":"bigbes@gmail.com","created_at":"2026-07-17T14:37:26Z","created_by":"Eugene Blikh","updated_at":"2026-07-17T14:37:26Z"}{"design":"DECISION (verified on git 2.55.0, 2026-07-17):\n\nSPLIT roles by whether they write code.\n\nADVISORY roles (research/review/design — read parent WIP, return TEXT, publish nothing): each child gets a DETACHED-HEAD worktree at the parent's tip commit:\n git worktree add --detach \u003cchild-wt\u003e \u003cparent-tip-sha\u003e\nProven: child sees parent's uncommitted-into-branch WIP (the parent's committed tip), runs on 'HEAD (no branch)', and any commits it makes do NOT move the parent's agent/task-\u003cid\u003e branch. Teardown (git worktree remove) leaves only unreferenced commits — no branch leak, no merge. This is the recommended FIRST and possibly ONLY implementation.\n\nWRITER roles (produce code that must land on the parent's branch): DEFERRED. They need a real branch plus a merge story, and note that gitDiffStat/gitLogOneline compute \u003cdefault\u003e..HEAD — a writer child branched off agent/task-\u003cid\u003e would misattribute ALL of the parent's work as the child's diff, so a writer child needs a different diff base (merge-base against the parent branch, not the repo default). Do not build until an advisory-only loop proves insufficient.\n\nConfirmed anti-pattern: git refuses 'worktree add \u003cpath\u003e agent/task-X' while X's worktree holds that branch ('already used by worktree at ...'), so a child can never simply enter the parent's branch.\n\nCODE SEAM for ah-0ge.1: the runner's worktree creation (internal/runner/commands.go gitWorktreeAddNewBranch, base=default) needs a base-override path for child tasks: detached add at the parent tip instead of a new branch off default. Child worktree path can follow the normal \u003cwork_root\u003e/\u003cslug\u003e/task-\u003cchildid\u003e convention; only the base differs."}NULL2026-07-17T18:49:20Z
019f70c4-9afa-7a16-a35e-03cab283f63aah-9r4closedEugene BlikhDecided: advisory children use detached-HEAD worktree at parent tip (verified git 2.55.0); writer children deferred. Full rationale + code seam in the design field.NULL2026-07-17T18:49:20Z
019f70c7-3b74-73d8-ba87-59448902fd8eah-gs7updatedEugene Blikh{"id":"ah-gs7","title":"Ultrapack designer/validator roles via config + skills (human-scheduled)","description":"Ultrapack (github.com/bigbes/ultrapack) is an OpenCode pack, but its value is the skills (udesign/uplan/uexecute/uverify/ureview), and pi implements the Agent Skills standard — so the skills load unmodified via --skill with no porting. Stage 2 already delivers --skill materialization, task_types and per-task frontmatter roles, so multi-role work needs ZERO daemon code today: add designer/validator roles to config pointing at ultrapack skill packages under skills_dir, and let a human drag cards between them. State carries between runs in docs/tasks/\u003cslug\u003e.md on the task branch. Do this BEFORE automating the handoff (ah-0ge slice): it validates whether the roles are actually good while the orchestration is still free.\nUltrapack agents/ do NOT get ported — see the delegation-loop beads; agents become roles, not subagents.","design":"Roles are {model, prompt} today (internal/config/config.go:72). Fork ultrapack skills into skills_dir packages; rewrite @implementer/@explorer/@reviewer subagent references (uplan/SKILL.md:126-128, uexecute/SKILL.md:37, handsoff/SKILL.md:35) out of the skill bodies — pi has no @-mention dispatch. Designer role MUST use ultrapack's handsoff skill: udesign/SKILL.md says 'Nothing is planned or written until the user approves', which deadlocks a board-driven run until the watchdog kills it as stalled.","acceptance_criteria":"A task labeled for the designer role produces a docs/tasks/\u003cslug\u003e.md with a Design section and lands In Review without stalling; dragging it to Ready under the validator role produces a review against that same file on the same branch.","notes":"VERIFIED 2026-07-17 on pi 0.73.1: ultrapack skills load unmodified via --skill. Clean test (neutral empty cwd, tools on): --no-skills alone -\u003e catalog NONE; --no-skills --skill skills/udesign --skill skills/uplan -\u003e catalog is EXACTLY {udesign, uplan}. Determinism property (SPEC §9: explicit --skill under --no-skills = intended set only) holds in practice. Probe gotchas for reruns: (1) run from a dir with no skills/ folder or the model just ls-es it and reports dir names; (2) do NOT use --no-tools — pi exposes skills THROUGH a tool, so --no-tools hides even loaded skills.","status":"open","priority":2,"issue_type":"feature","owner":"bigbes@gmail.com","created_at":"2026-07-17T14:37:25Z","created_by":"Eugene Blikh","updated_at":"2026-07-17T15:38:50Z"}{"notes":"HEADLESS BEHAVIOR VERIFIED 2026-07-17 (opencode/claude-haiku-4-5, pi -p --mode json, udesign loaded via --skill on a throwaway repo): the designer run did NOT deadlock. 9 turns, read/bash/write tools, stopReason=stop, and it WROTE docs/tasks/mul-div.md following udesign's structure (Invariants/Principles/Assumptions/Unknowns + TDD decision).\n\nCRITICAL REQUIREMENT for the designer role prompt: this only worked because the rendered PROMPT explicitly neutralized udesign's collaborative-approval framing — 'No human is available; you will not receive a reply; make reasonable assumptions and record them; do not end by asking a question; WRITE the result to \u003cpath\u003e'. A naive 'design X' prompt would likely trigger the skill's 'nothing until the user approves' path and land In Review with only a question and no artifact. So prompts/designer.md MUST carry the autonomy+write-artifact framing (a lighter alternative to loading the full handsoff skill; both work). Same pattern will apply to validator/ureview.\n\nAside: openai-codex provider on this box is a ChatGPT account and rejects some models (gpt-5.2 -\u003e 400 invalid_request). Use opencode/* or deepseek/* for local pi tests; daemon uses litellm anyway."}NULL2026-07-17T18:52:12Z
019f70cd-36bd-7e63-9b16-e8df7643b106ah-0ge.1claimedEugene Blikh{"id":"ah-0ge.1","title":"Agent-created tasks via .task/tasks.json file channel","description":"First slice of the delegation loop: agent X declares the child roles it needs, X exits, the reconciler creates those tasks. Deliberately NOT the full ah-0ge tools API — no bearer tokens, no ahub tool CLI, no HTTP endpoints. X writes .task/tasks.json on the way out; the reconciler reads it at run end, the same way .task/question.json is already reserved (SPEC:392) in a directory internal/runner/taskfiles.go already owns.\nA file channel can only be read at run END, which would cripple an interactive ask-user loop but is EXACTLY the semantics wanted here ('agent X stops'). That constraint is what makes this slice small.\nServer-side policy from the ah-0ge epic still applies: gen\u003c=2, per-session caps, dedup, project allowlist. A child that spawns children that spawn children fills the board.","design":"Child tasks get a role (must exist in cfg.Roles) + a task body. Open: do children land in Ready directly (agent-\u003eagent, per the proposal) or in Triage for a human to release (per SPEC §14.4 as written)? Triage is the safer default and can be relaxed later via config.","acceptance_criteria":"A run whose agent writes .task/tasks.json with two child role tasks results in two new board tasks with those roles; a malformed or over-cap file bounces the parent rather than creating anything.","status":"open","priority":3,"issue_type":"feature","owner":"bigbes@gmail.com","created_at":"2026-07-17T14:38:02Z","created_by":"Eugene Blikh","updated_at":"2026-07-17T14:38:02Z"}{"assignee":"Eugene Blikh","status":"in_progress"}NULL2026-07-17T18:58:44Z
019f70dd-4b62-71e8-9068-8281280426bcah-0ge.1updatedEugene Blikh{"id":"ah-0ge.1","title":"Agent-created tasks via .task/tasks.json file channel","description":"First slice of the delegation loop: agent X declares the child roles it needs, X exits, the reconciler creates those tasks. Deliberately NOT the full ah-0ge tools API — no bearer tokens, no ahub tool CLI, no HTTP endpoints. X writes .task/tasks.json on the way out; the reconciler reads it at run end, the same way .task/question.json is already reserved (SPEC:392) in a directory internal/runner/taskfiles.go already owns.\nA file channel can only be read at run END, which would cripple an interactive ask-user loop but is EXACTLY the semantics wanted here ('agent X stops'). That constraint is what makes this slice small.\nServer-side policy from the ah-0ge epic still applies: gen\u003c=2, per-session caps, dedup, project allowlist. A child that spawns children that spawn children fills the board.","design":"Child tasks get a role (must exist in cfg.Roles) + a task body. Open: do children land in Ready directly (agent-\u003eagent, per the proposal) or in Triage for a human to release (per SPEC §14.4 as written)? Triage is the safer default and can be relaxed later via config.","acceptance_criteria":"A run whose agent writes .task/tasks.json with two child role tasks results in two new board tasks with those roles; a malformed or over-cap file bounces the parent rather than creating anything.","status":"in_progress","priority":3,"issue_type":"feature","assignee":"Eugene Blikh","owner":"bigbes@gmail.com","created_at":"2026-07-17T14:38:02Z","created_by":"Eugene Blikh","updated_at":"2026-07-17T15:58:45Z","started_at":"2026-07-17T15:58:45Z"}{"notes":"IMPLEMENTED 2026-07-17. Agent writes .task/tasks.json ({tasks:[{role,title,body}]}); a SUCCESSFUL run's finalize reads it and creates one board card per entry under its role (frontmatter 'role: X') in the configured target bucket.\n\nDecisions made during implementation:\n- Ready vs Triage: config knob agent_tasks.target_bucket, DEFAULT 'triage' (spec §14.4-aligned, safe: human vets agent-created work). Flip to 'ready' for the full auto agent→agent loop. Documented in config.example.yaml + SPEC §12.\n- 'Bounce' semantics: malformed/over-cap/unknown-role/empty-title creates NOTHING (atomic) and posts a rejection comment on the parent; the parent's OWN work still finalizes to In Review. Chose comment-not-card-move because moving the parent to Triage collides with the state model (triage is a parked bucket, not a task State, and the parent has a persisted record). Stronger card-move bounce deferred.\n- gen\u003c=2 cap DEFERRED to ah-0ge.2: needs task lineage (parent link) which doesn't exist yet. Only the per-run COUNT cap (max_per_run, default 5) is enforced now.\n- Mid-creation transport failure keeps already-created children (can't un-create) and stops; logged. finalize isn't retried post-InReview.\n\nNew surface: domain.RequestedTask; ports.Board.CreateTask + ports.NewTask; ports.Runner.RequestedTasks; runner.readTasksFile + PiZellij.RequestedTasks; vikunja.Client.CreateTask (PUT /projects/{id}/tasks then MoveToBucket); reconcile.spawnChildTasks/validateRequestedTasks/childDescription; config.AgentTasks. Tests: reconcile (spawn 2, unknown-role bounce, over-cap bounce, malformed bounce), runner (readTasksFile absent/valid/malformed), vikunja (CreateTask HTTP path), config (defaults + 2 validation failures). Full suite + e2e green under GOFLAGS=-mod=readonly."}NULL2026-07-17T19:16:18Z
019f70dd-4db9-79d7-bbb7-438bcc944910ah-0ge.1closedEugene BlikhImplemented and tested: agent-created child tasks via .task/tasks.json file channel. Acceptance met (two children created; malformed/over-cap bounces atomically). Config knob defaults to Triage; gen-cap deferred to ah-0ge.2.NULL2026-07-17T19:16:19Z
019f712f-0ce2-79eb-b2de-26915f09aef8ah-0ge.2claimedEugene Blikh{"id":"ah-0ge.2","title":"Parent auto-Block/unblock join on child completion","description":"The join half of the delegation loop, per SPEC §14.4 'parent auto-Block/unblock'. When X spawns children it parks in the Blocked bucket — which already exists as a parked bucket that never claims and never kills (SPEC:174) — and returns to Ready when all children reach a terminal state. Needs a parent link (tasks.parent_id in internal/store/schema.sql, or Vikunja task relations) plus somewhere to hold each child's result for the resume payload.\nUNSPECIFIED IN THE SPEC AND NEEDS A DECISION: partial failure. Y done, Z failed — does X resume with the failure reported, bounce to Failed, or go to Triage? §14 says auto-unblock but not what unblock means when a child died.","acceptance_criteria":"X with children Y,Z sits in Blocked while either runs and returns to Ready only once both are terminal; the partial-failure path is decided and covered by a transitions test.","status":"open","priority":3,"issue_type":"feature","owner":"bigbes@gmail.com","created_at":"2026-07-17T14:38:03Z","created_by":"Eugene Blikh","updated_at":"2026-07-17T14:38:03Z"}{"assignee":"Eugene Blikh","status":"in_progress"}NULL2026-07-17T20:45:36Z
019f7138-1076-7d84-9b11-fdb4d8a0cf24ah-0ge.2updatedEugene Blikh{"id":"ah-0ge.2","title":"Parent auto-Block/unblock join on child completion","description":"The join half of the delegation loop, per SPEC §14.4 'parent auto-Block/unblock'. When X spawns children it parks in the Blocked bucket — which already exists as a parked bucket that never claims and never kills (SPEC:174) — and returns to Ready when all children reach a terminal state. Needs a parent link (tasks.parent_id in internal/store/schema.sql, or Vikunja task relations) plus somewhere to hold each child's result for the resume payload.\nUNSPECIFIED IN THE SPEC AND NEEDS A DECISION: partial failure. Y done, Z failed — does X resume with the failure reported, bounce to Failed, or go to Triage? §14 says auto-unblock but not what unblock means when a child died.","acceptance_criteria":"X with children Y,Z sits in Blocked while either runs and returns to Ready only once both are terminal; the partial-failure path is decided and covered by a transitions test.","status":"in_progress","priority":3,"issue_type":"feature","assignee":"Eugene Blikh","owner":"bigbes@gmail.com","created_at":"2026-07-17T14:38:03Z","created_by":"Eugene Blikh","updated_at":"2026-07-17T17:45:37Z","started_at":"2026-07-17T17:45:37Z"}{"notes":"PARTIAL 2026-07-17. Split delivered: the parent↔child LINEAGE + DEPTH CAP is done and tested; the behavioral block/wait/resume JOIN is deferred and coupled to ah-0ge.3 (see finding below).\n\nDELIVERED (green, GOFLAGS=-mod=readonly):\n- store schema v3: task_parents(child_id PK, parent_id, generation, created_at) + migration [2]-\u003e[3].\n- ports.Store + store: RecordChild, GenerationOf, ChildIDsOf (idempotent on child_id).\n- config.AgentTasks.MaxGeneration (default 2, must be positive).\n- reconcile.spawnChildTasks now enforces the depth cap (a task at generation \u003e= MaxGeneration cannot delegate; childGen = parentGen+1) and records each child's lineage on creation; 'spawned_tasks' event carries generation.\n- Tests: store lineage round-trip + idempotency; reconcile lineage-recorded + over-depth rejection; config default + negative-generation validation; migration tests updated to schemaVersion + task_parents presence.\n\nARCHITECTURAL FINDING (blocks the join; needs a decision):\nah-0ge.2 and ah-0ge.3 are INSEPARABLE. If a blocked parent 'unblocks' into a plain re-claim without its pi session context, it re-runs from scratch, re-spawns the same children, and blocks again — infinite re-delegation (bounded only by caps). So 'unblock' is only correct AS 'resume-with-context', which is ah-0ge.3. Also, a delegating parent must WAIT in a real state: 'blocked' is currently a parked BUCKET, not a task State, so the join requires promoting blocked to a normative State (domain.States/Valid/CanClaim/transitions + the reconcile bucket switch) — SPEC §14.4 explicitly sanctions this ('blocked earns real semantics in Stage 4').\n\nDECISIONS captured for the join (from the user): child counts as done at IN REVIEW (not Done); partial failure -\u003e resume the parent reporting each child's outcome, parent may retry a couple of times (bounded by MaxGeneration + a future per-parent round cap).\n\nRECOMMENDATION: implement the join + resume as ONE unit (merge ah-0ge.2 remaining scope with ah-0ge.3), starting by promoting 'blocked' to a real State."}NULL2026-07-17T20:55:27Z
019f7138-3740-71ec-b759-20a6fadd8286ah-0ge.3updatedEugene Blikh{"id":"ah-0ge.3","title":"Resume parent via pi --session with child results as a new attempt","description":"Closes the loop: X comes back from Blocked and continues WITH its original context rather than starting cold. runs.pi_session_id is already a column in internal/store/schema.sql and pi supports --session \u003cpath|id\u003e (0.73.1, also --session-dir), so this is mostly plumbing — but two things need care.\n(1) Session survival: X's pi session must outlive the park. Pin --session-dir explicitly rather than relying on a default location, and confirm X's worktree is not reclaimed while parked.\n(2) Result transfer contract: Y's output has to serialize out of Y's run, through the board, and into X's resume prompt. Needs a defined shape and a size bound — in-process subagents return text into the parent's context for free, this path does not.","design":"Resume is a NEW attempt on X (runs table already keys on (task_id, attempt)), so watchdog/cost/event plumbing is unchanged. Prompt gets an extra rendered section carrying each child's role + result.","acceptance_criteria":"X resumes after its children finish, its pi session id is unchanged across the park, the new attempt shows the children's results in the rendered prompt, and an oversized child result is truncated rather than breaking the resume.","status":"open","priority":3,"issue_type":"feature","owner":"bigbes@gmail.com","created_at":"2026-07-17T14:38:04Z","created_by":"Eugene Blikh","updated_at":"2026-07-17T14:38:04Z"}{"notes":"COUPLING (2026-07-17): inseparable from ah-0ge.2's behavioral join — see ah-0ge.2 notes. 'Unblock' is only correct as this resume-with-context, else the parent re-runs from scratch and re-spawns children (infinite re-delegation). Recommend implementing ah-0ge.2 (remaining join) + ah-0ge.3 as one unit, starting by promoting 'blocked' to a real domain.State. Lineage foundation (task_parents, ChildIDsOf) already landed under ah-0ge.2."}NULL2026-07-17T20:55:37Z