~bigbes/agents-dev · parade

main · last commit 13 days ago · 7g0stsfu

← Back to the parade

ah-nyl.4 runner: pi+zellij implementation + ahub-run supervisor Past Stand

status: closed P1 task
bd reopen ah-nyl.4
Created byEugene Blikh
Ownerbigbes@gmail.com
Created2026-07-12T23:35:16Z
Started2026-07-12T23:55:04Z
Updated2026-07-13T00:20:36Z
Closed2026-07-13T00:20:36Z
Description
Implement internal/runner + cmd/ahub-run per docs/SPEC.md SS9 (read SPEC fully; SS6, SS9 normative). This is the trickiest package — the SS9 contract (worktree layout, .task/ files, status precedence) is normative; follow it to the letter.

Deliverables:
- internal/runner: New(cfg *config.Config, logger *slog.Logger) *PiZellij implementing ports.Runner (compile-time check var _ ports.Runner = ...).
  - Start: create/reuse worktree + branch per SS9 (git -C <repo> worktree add ...; handle existing worktree dir and existing branch for retries), write .task/PROMPT.md and .task/meta.json, worktree-local ignore via the resolved git-dir info/exclude per SS9, ensure zellij session (zellij attach --create-background task-<id>), spawn the pane (zellij --session task-<id> run --cwd <worktree> -- ahub-run --task-id N --attempt K --report-url <url> -- pi --mode json -p @.task/PROMPT.md --model <model> --no-skills --no-extensions [pi_args...]). Return RunInfo.
  - Status: precedence per SS9 — exit.json => Completed (outcome success/error by code); else session alive in `zellij list-sessions --short` => Running with LastEvent=mtime(events.jsonl); else Completed with OutcomeCrashed, exit -1. Parse PiSession + CostUSD from events.jsonl leniently: scan lines as loose JSON maps; session id from the first object that has a plausible session identifier; cost accumulated from usage/cost fields when present. IMPORTANT: pi 0.70.2 is installed locally — empirically capture a real `pi --mode json -p 'say hi'` JSONL sample (any cheap/configured model, or ask for the shape via `pi --help` + a dry attempt; if no model is invocable offline, mark the parser 'best-effort, fixture-based' and derive fixtures from pi's documented event shape), commit the sample as a testdata fixture, and pin the parser to it.
  - Kill: zellij kill-session + best-effort delete-session. Summary: git log/diff per SS9.
  - ALL zellij/pi/git argv construction centralized in commands.go with unit tests asserting exact argv (SS9 requirement).
- cmd/ahub-run: supervisor per SS9 contract — tee child stdout to .task/events.jsonl (stderr passthrough), atomic exit.json (tmp+rename), best-effort POST to --report-url (2s timeout, 1 retry), signal-death -> 128+sig, --keep-pane default true iff $ZELLIJ set (then print resume hint + exec $SHELL), false => exit with child code.

Tests: stub `zellij`/`pi`/(where sensible `git` is real — use real git with a t.TempDir() repo for worktree tests) as executable scripts prepended to PATH; cover: worktree create+reuse, argv construction, status precedence matrix (exit.json / alive / gone), events parsing from fixture, ahub-run end-to-end via os/exec (tee, atomic exit.json, report POST to httptest, exit-code mapping). No sleeps >100ms; no real zellij sessions in tests.

Constraints: work ONLY under internal/runner/ and cmd/ahub-run/. No go.mod changes, no other packages, no .beads/. Build/test ONLY yours: go build ./internal/runner/... ./cmd/ahub-run/... && go vet <same> && go test <same>. Commit 'runner: ...' staging only your paths. Do NOT push.

Depends on

  • ah-nyl — Stage 1 MVP: poll-driven happy path parent-child closed
  • ah-nyl.1 — foundation: go module, domain, ports, config blocks closed

Depended on by

  • ah-nyl.6 — wiring: httpapi + agenthubd + ahub CLIs blocks

Unblocks — everything waiting on this, transitively

  • ah-nyl.6 — wiring: httpapi + agenthubd + ahub CLIs blocks closed
  • ah-nyl.7 — e2e: harness with fake vikunja + stub pi blocks closed
  • ah-nyl.8 — refactor: adopt go.bigb.es/auxilia (scribe/culpa/steward) where it pays blocks closed

No comments.

Close reason

landed 4348d2b, 37 tests race-clean, empirical pi JSONL fixtures + zellij probes; SPEC corrections: git-common-dir exclude path, attach --create-background not idempotent (exit 1 tolerated), retry clears stale exit.json
  • Eugene Blikh added under epic ah-nyl · 2026-07-13T02:35:16Z
  • Eugene Blikh added dependency on ah-nyl.1 · 2026-07-13T02:35:16Z
  • Eugene Blikh created the issue · 2026-07-13T02:35:16Z
  • Eugene Blikh ah-nyl.6 now depends on this · 2026-07-13T02:35:54Z
  • Eugene Blikh changed status to in_progress · 2026-07-13T02:55:04Z
  • Eugene Blikh closed the issue · 2026-07-13T03:20:35Z
    landed 4348d2b, 37 tests race-clean, empirical pi JSONL fixtures + zellij probes; SPEC corrections: git-common-dir exclude path, attach --create-background not idempotent (exit 1 tolerated), retry clears stale exit.json
  • Eugene Blikh added label milestone:stage-1 · 2026-07-20T03:08:46Z
  • Eugene Blikh removed label milestone:stage-1 · 2026-07-20T03:10:21Z
Stored rows — what this pane was built from, as read
issues 1 row
id ah-nyl.4
content_hash ff6bd742ed8006517b016443e69e35e99531123b2198633480125843c1ee2f40
title runner: pi+zellij implementation + ahub-run supervisor
description Implement internal/runner + cmd/ahub-run per docs/SPEC.md SS9 (read SPEC fully; SS6, SS9 normative). This is the trickiest package — the SS9 contract (worktree layout, .task/ files, status precedence) is normative; follow it to the letter. Deliverables: - internal/runner: New(cfg *config.Config, logger *slog.Logger) *PiZellij implementing ports.Runner (compile-time check var _ ports.Runner = ...). - Start: create/reuse worktree + branch per SS9 (git -C <repo> worktree add ...; handle existing worktree dir and existing branch for retries), write .task/PROMPT.md and .task/meta.json, worktree-local ignore via the resolved git-dir info/exclude per SS9, ensure zellij session (zellij attach --create-background task-<id>), spawn the pane (zellij --session task-<id> run --cwd <worktree> -- ahub-run --task-id N --attempt K --report-url <url> -- pi --mode json -p @.task/PROMPT.md --model <model> --no-skills --no-extensions [pi_args...]). Return RunInfo. - Status: precedence per SS9 — exit.json => Completed (outcome success/error by code); else session alive in `zellij list-sessions --short` => Running with LastEvent=mtime(events.jsonl); else Completed with OutcomeCrashed, exit -1. Parse PiSession + CostUSD from events.jsonl leniently: scan lines as loose JSON maps; session id from the first object that has a plausible session identifier; cost accumulated from usage/cost fields when present. IMPORTANT: pi 0.70.2 is installed locally — empirically capture a real `pi --mode json -p 'say hi'` JSONL sample (any cheap/configured model, or ask for the shape via `pi --help` + a dry attempt; if no model is invocable offline, mark the parser 'best-effort, fixture-based' and derive fixtures from pi's documented event shape), commit the sample as a testdata fixture, and pin the parser to it. - Kill: zellij kill-session + best-effort delete-session. Summary: git log/diff per SS9. - ALL zellij/pi/git argv construction centralized in commands.go with unit tests asserting exact argv (SS9 requirement). - cmd/ahub-run: supervisor per SS9 contract — tee child stdout to .task/events.jsonl (stderr passthrough), atomic exit.json (tmp+rename), best-effort POST to --report-url (2s timeout, 1 retry), signal-death -> 128+sig, --keep-pane default true iff $ZELLIJ set (then print resume hint + exec $SHELL), false => exit with child code. Tests: stub `zellij`/`pi`/(where sensible `git` is real — use real git with a t.TempDir() repo for worktree tests) as executable scripts prepended to PATH; cover: worktree create+reuse, argv construction, status precedence matrix (exit.json / alive / gone), events parsing from fixture, ahub-run end-to-end via os/exec (tee, atomic exit.json, report POST to httptest, exit-code mapping). No sleeps >100ms; no real zellij sessions in tests. Constraints: work ONLY under internal/runner/ and cmd/ahub-run/. No go.mod changes, no other packages, no .beads/. Build/test ONLY yours: go build ./internal/runner/... ./cmd/ahub-run/... && go vet <same> && go test <same>. Commit 'runner: ...' staging only your paths. Do NOT push.
design
acceptance_criteria
notes
status closed
priority 1
issue_type task
assignee NULL
estimated_minutes NULL
created_at 2026-07-12T23:35:16Z
created_by Eugene Blikh
owner bigbes@gmail.com
updated_at 2026-07-13T00:20:36Z
closed_at 2026-07-13T00:20:36Z
closed_by_session
external_ref NULL
spec_id
compaction_level 0
compacted_at NULL
compacted_at_commit NULL
original_size NULL
sender
ephemeral 0
wisp_type
pinned 0
is_template 0
mol_type
work_type
source_system
metadata �{}
source_repo
close_reason landed 4348d2b, 37 tests race-clean, empirical pi JSONL fixtures + zellij probes; SPEC corrections: git-common-dir exclude path, attach --create-background not idempotent (exit 1 tolerated), retry clears stale exit.json
event_kind
actor
target
payload
await_type
await_id
timeout_ns 0
waiters
hook_bead
role_bead
agent_state
last_activity NULL
role_type
rig
due_at NULL
defer_until NULL
no_history 0
started_at 2026-07-12T23:55:04Z
is_blocked 0
dependencies 3 rows
id 26b2a07a-7dd9-5e0a-951f-b91452a60822
issue_id ah-nyl.4
type parent-child
created_at 2026-07-13T02:35:16Z
created_by Eugene Blikh
metadata �{}
thread_id
depends_on_issue_id ah-nyl
depends_on_wisp_id NULL
depends_on_external NULL
id 3d8e93c3-909c-5d9e-85df-7bc6e0e2b5ab
issue_id ah-nyl.6
type blocks
created_at 2026-07-13T02:35:54Z
created_by Eugene Blikh
metadata �{}
thread_id
depends_on_issue_id ah-nyl.4
depends_on_wisp_id NULL
depends_on_external NULL
id d53dcd44-b88d-5f2b-9657-427bb2b99459
issue_id ah-nyl.4
type blocks
created_at 2026-07-13T02:35:16Z
created_by Eugene Blikh
metadata �{}
thread_id
depends_on_issue_id ah-nyl.1
depends_on_wisp_id NULL
depends_on_external NULL
events 5 rows
id 019f58af-5f36-73b9-b949-03c66a15432a
issue_id ah-nyl.4
event_type created
actor Eugene Blikh
old_value
new_value
comment NULL
created_at 2026-07-13T02:35:16Z
id 019f58c1-8183-729f-af88-6eec7c4ef330
issue_id ah-nyl.4
event_type status_changed
actor Eugene Blikh
old_value {"id":"ah-nyl.4","title":"runner: pi+zellij implementation + ahub-run supervisor","description":"Implement internal/runner + cmd/ahub-run per docs/SPEC.md SS9 (read SPEC fully; SS6, SS9 normative). This is the trickiest package — the SS9 contract (worktree layout, .task/ files, status precedence) is normative; follow it to the letter.\n\nDeliverables:\n- internal/runner: New(cfg *config.Config, logger *slog.Logger) *PiZellij implementing ports.Runner (compile-time check var _ ports.Runner = ...).\n - Start: create/reuse worktree + branch per SS9 (git -C \u003crepo\u003e worktree add ...; handle existing worktree dir and existing branch for retries), write .task/PROMPT.md and .task/meta.json, worktree-local ignore via the resolved git-dir info/exclude per SS9, ensure zellij session (zellij attach --create-background task-\u003cid\u003e), spawn the pane (zellij --session task-\u003cid\u003e run --cwd \u003cworktree\u003e -- ahub-run --task-id N --attempt K --report-url \u003curl\u003e -- pi --mode json -p @.task/PROMPT.md --model \u003cmodel\u003e --no-skills --no-extensions [pi_args...]). Return RunInfo.\n - Status: precedence per SS9 — exit.json =\u003e Completed (outcome success/error by code); else session alive in `zellij list-sessions --short` =\u003e Running with LastEvent=mtime(events.jsonl); else Completed with OutcomeCrashed, exit -1. Parse PiSession + CostUSD from events.jsonl leniently: scan lines as loose JSON maps; session id from the first object that has a plausible session identifier; cost accumulated from usage/cost fields when present. IMPORTANT: pi 0.70.2 is installed locally — empirically capture a real `pi --mode json -p 'say hi'` JSONL sample (any cheap/configured model, or ask for the shape via `pi --help` + a dry attempt; if no model is invocable offline, mark the parser 'best-effort, fixture-based' and derive fixtures from pi's documented event shape), commit the sample as a testdata fixture, and pin the parser to it.\n - Kill: zellij kill-session + best-effort delete-session. Summary: git log/diff per SS9.\n - ALL zellij/pi/git argv construction centralized in commands.go with unit tests asserting exact argv (SS9 requirement).\n- cmd/ahub-run: supervisor per SS9 contract — tee child stdout to .task/events.jsonl (stderr passthrough), atomic exit.json (tmp+rename), best-effort POST to --report-url (2s timeout, 1 retry), signal-death -\u003e 128+sig, --keep-pane default true iff $ZELLIJ set (then print resume hint + exec $SHELL), false =\u003e exit with child code.\n\nTests: stub `zellij`/`pi`/(where sensible `git` is real — use real git with a t.TempDir() repo for worktree tests) as executable scripts prepended to PATH; cover: worktree create+reuse, argv construction, status precedence matrix (exit.json / alive / gone), events parsing from fixture, ahub-run end-to-end via os/exec (tee, atomic exit.json, report POST to httptest, exit-code mapping). No sleeps \u003e100ms; no real zellij sessions in tests.\n\nConstraints: work ONLY under internal/runner/ and cmd/ahub-run/. No go.mod changes, no other packages, no .beads/. Build/test ONLY yours: go build ./internal/runner/... ./cmd/ahub-run/... \u0026\u0026 go vet \u003csame\u003e \u0026\u0026 go test \u003csame\u003e. Commit 'runner: ...' staging only your paths. Do NOT push.\n","status":"open","priority":1,"issue_type":"task","owner":"bigbes@gmail.com","created_at":"2026-07-12T23:35:16Z","created_by":"Eugene Blikh","updated_at":"2026-07-12T23:35:16Z"}
new_value {"status":"in_progress"}
comment NULL
created_at 2026-07-13T02:55:04Z
id 019f58d8-debe-714c-9df7-dafb582290f8
issue_id ah-nyl.4
event_type closed
actor Eugene Blikh
old_value
new_value landed 4348d2b, 37 tests race-clean, empirical pi JSONL fixtures + zellij probes; SPEC corrections: git-common-dir exclude path, attach --create-background not idempotent (exit 1 tolerated), retry clears stale exit.json
comment NULL
created_at 2026-07-13T03:20:35Z
id 019f7cda-9087-7ead-b8b5-5c22d84dd344
issue_id ah-nyl.4
event_type label_added
actor Eugene Blikh
old_value NULL
new_value NULL
comment Added label: milestone:stage-1
created_at 2026-07-20T03:08:46Z
id 019f7cdc-04c5-78be-96af-bfcbb9e8a7e1
issue_id ah-nyl.4
event_type label_removed
actor Eugene Blikh
old_value NULL
new_value NULL
comment Removed label: milestone:stage-1
created_at 2026-07-20T03:10:21Z