Skip to content

feat(specialist): add lifecycle metadata - #106

Merged
gnanam1990 merged 1 commit into
mainfrom
feat/specialist-hook-events
Jun 7, 2026
Merged

feat(specialist): add lifecycle metadata#106
gnanam1990 merged 1 commit into
mainfrom
feat/specialist-hook-events

Conversation

@anandh8x

@anandh8x anandh8x commented Jun 7, 2026

Copy link
Copy Markdown
Collaborator

Summary:

  • adds specialistStart/specialistStop hook events and parser coverage
  • adds session tag/depth metadata for specialist child runs
  • persists tag/depth through exec session preparation and child session lineage
  • surfaces tag/depth in session snapshots and session list output

Scope:

Tests:

  • GOCACHE=/tmp/zero-go-cache go test ./internal/hooks ./internal/sessions ./internal/cli ./internal/zerocommands
  • GOCACHE=/tmp/zero-go-cache go test ./...
  • git diff --check

Summary by CodeRabbit

Release Notes

  • New Features
    • Sessions now support Tag and Depth metadata, configurable via --tag and --depth command-line options.
    • Tag and depth fields now display in session list output.
    • Added new hook event types for specialist workflow lifecycle events.

@github-actions

github-actions Bot commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

Zero automated PR review

Verdict: No blockers found

Blockers

  • None found.

Validation

  • [pass] Diff hygiene: git diff --check
  • [pass] Tests: go test ./...
  • [pass] Build: go run ./cmd/zero-release build
  • [pass] Smoke build: go run ./cmd/zero-release smoke

Scope

Head: 92b35ed3dbdb
Changed files (12): internal/cli/exec.go, internal/cli/exec_test.go, internal/cli/sessions.go, internal/cli/sessions_test.go, internal/hooks/hooks.go, internal/hooks/hooks_test.go, internal/sessions/exec_session.go, internal/sessions/lineage.go, internal/sessions/store.go, internal/sessions/store_test.go, internal/zerocommands/contracts.go, internal/zerocommands/contracts_test.go

This deterministic review checks validation status and basic diff hygiene. A human reviewer still owns product judgment and design quality.

@coderabbitai

coderabbitai Bot commented Jun 7, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 3796312e-b655-4459-a286-711d73006a73

📥 Commits

Reviewing files that changed from the base of the PR and between ae6c959 and 92b35ed.

📒 Files selected for processing (12)
  • internal/cli/exec.go
  • internal/cli/exec_test.go
  • internal/cli/sessions.go
  • internal/cli/sessions_test.go
  • internal/hooks/hooks.go
  • internal/hooks/hooks_test.go
  • internal/sessions/exec_session.go
  • internal/sessions/lineage.go
  • internal/sessions/store.go
  • internal/sessions/store_test.go
  • internal/zerocommands/contracts.go
  • internal/zerocommands/contracts_test.go

Walkthrough

This PR extends the session system to track specialist execution metadata via Tag (identifier string) and Depth (nesting level integer). The fields thread through session creation, CLI flags, lineage, hooks, and API contracts with matching test updates throughout.

Changes

Specialist Metadata (Tag and Depth) Support

Layer / File(s) Summary
Session metadata schema and validation
internal/sessions/store.go, internal/sessions/store_test.go
Metadata, CreateInput, and ChildInput now include Tag and Depth fields. Store.Create validates that Depth is non-negative, trims whitespace from Tag, and persists both into session records.
Session creation and child lineage
internal/sessions/exec_session.go, internal/sessions/lineage.go
PrepareExecOptions carries Tag and Depth through to PrepareExec, which passes them to session creation. Child sessions receive and propagate the metadata; lineage events include tag and depth in parent–child linking payloads.
Hook system events for specialists
internal/hooks/hooks.go, internal/hooks/hooks_test.go
New EventSpecialistStart and EventSpecialistStop constants; eventSupportsMatcher helper restricts matcher validation to tool-related events; parseEvent recognizes specialist events and updates error messages.
CLI flags and session display
internal/cli/exec.go, internal/cli/sessions.go, internal/cli/exec_test.go, internal/cli/sessions_test.go
--tag and --depth flags flow from CLI into PrepareExecOptions; formatSessionSnapshotLine conditionally renders tag=<value> in session list output when Tag is non-empty.
API contract and snapshot serialization
internal/zerocommands/contracts.go, internal/zerocommands/contracts_test.go
SessionSnapshot adds optional JSON fields Tag and Depth; SessionSnapshotFromMetadata populates them from persisted session metadata for API responses.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • Gitlawb/zero#104: Introduces specialist execution metadata (--tag and --depth flags) that flow through internal/cli/exec.go session preparation into the data model.
  • Gitlawb/zero#68: Builds on session lineage backend (CreateChild, childLinkPayload) to propagate new metadata fields through child session creation and lineage events.

Suggested reviewers

  • gnanam1990
  • Vasanthdev2004
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(specialist): add lifecycle metadata' directly and accurately summarizes the main change: adding lifecycle-related metadata (tag and depth) for specialist sessions.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/specialist-hook-events

Comment @coderabbitai help to get the list of available commands and usage tips.

@anandh8x
anandh8x requested a review from gnanam1990 June 7, 2026 05:26

@gnanam1990 gnanam1990 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review — clean, approving

Tidy, well-scoped metadata groundwork, and nicely tested. Highlights:

  • Hooks: specialistStart/specialistStop events added consistently — parseEvent accepts them with an updated error message, and the matcher check is refactored to a positive eventSupportsMatcher (beforeTool/afterTool only) so the new lifecycle events correctly reject matchers too. Covered by TestLoadConfigRejectsMatchersOnLifecycleHooks + TestSpecialistHookEventsLoadAndSelect.
  • Sessions: Tag/Depth flow through Metadata / CreateInput / ChildInput, and CreateChild routes through Create(), so the Depth < 0 guard and Tag trimming apply to child sessions too (verified). omitempty keeps existing JSON stable. Covered by TestStoreRejectsNegativeSessionDepth + TestPrepareExecPersistsSpecialistMetadataForNewSession.
  • CLI/contracts: tag/depth surfaced in zero sessions output and the SessionSnapshot contract.

go build/vet/go test ./... all green. Approving.

Non-blocking notes

  1. depth semantics coordination (continuing the thread from #104): depth now spans exec flags (#104), agent.Options.Depth (#104), and session Metadata.Depth (here). Worth making sure they all carry the same "specialist nesting level" meaning and converge cleanly with the upcoming task-runtime depth — so a child run's session depth == its agent nesting depth.
  2. childLinkPayload calls strings.TrimSpace(input.Tag) while Create() also trims Tag for the stored metadata — harmless redundancy, just noting.
  3. As stated in the PR, Tag/Depth are persisted/surfaced but not yet consumed by any runtime — fine as groundwork; flagging so it's a conscious staging step.

Nice incremental slice. 👍

🤖 Verified review via Claude Code.

@gnanam1990
gnanam1990 merged commit 561fe0b into main Jun 7, 2026
6 checks passed
gnanam1990 added a commit that referenced this pull request Jun 7, 2026
…store, file locking (#112)

* Session checkpoints & safe rewind: content-addressed blobs, atomic restore, file locking

Module 4 of the runtime-core split. Scope: internal/sessions only. 3-way merged cleanly onto main's #106 Tag/Depth work (preserved); no new deps (filelock uses stdlib syscall); build/vet/-race/windows-cross-compile/full-suite green.

- CaptureToolCheckpoint snapshots a tool's target files into content-addressed (sha256) blobs before a mutating tool runs; SnapshotForCheckpoint records file mode; oversize files are skipped, identical content deduped.

- RestoreToSequence reverts to a target sequence: applies only the closest-to-target checkpoint per path, verifies each blob's sha256 before writing, preserves file mode, and confines paths with EvalSymlinks (no symlink escape). ApplyRewind runs restore+truncate+prune+marker atomically under one session lock.

- Cross-process file lock (flock) serializes session mutations; Fork copies checkpoint blobs so a fork can rewind; writeMetadata uses a unique tmp suffix.

FORWARD: this is the persistence layer; the CLI 'zero sessions rewind' and the TUI '/rewind' + pre-tool checkpoint capture wiring land in later modules. Exercised here by checkpoint_test.go / rewind_test.go.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Address #112 review: capture-side confinement, atomic-only checkpoint API, Windows lock, test hygiene

- [critical/human blocker] snapshotForCheckpoint now confines every capture target with resolveWithinWorkspace (same EvalSymlinks/no-".." guard as restore) BEFORE stat/read, so a traversal/symlink target can't read files outside the workspace into a blob. os.Stat failures are classified correctly: only os.IsNotExist -> Absent (restore deletes); permission/IO/symlink-loop -> Skipped (restore leaves alone), instead of treating every failure as Absent. Regression test added (TestCaptureRejectsTraversalTargets).

- [major] SnapshotForCheckpoint unexported -> snapshotForCheckpoint: the blob writes and the referencing EventSessionCheckpoint must be committed atomically under one session lock, which only CaptureToolCheckpoint guarantees. Removes the unsafe snapshot-only external entry point (blob/event gap).

- [major] Windows: real LockFileEx/UnlockFileEx (filelock_windows.go) replacing the no-op, so cross-process/cross-Store session serialization holds on Windows too. No new deps (x/sys already required for the unix flock).

- [minor] checkpoint_test hygiene: check os.WriteFile/ReadDir/ReadFile/ReadEvents errors via helpers, add bounds checks before p.Files[0]/events[...] so setup failures fail at the source instead of panicking or passing spuriously.

- rewind restore: documented the residual symlink-swap TOCTOU (boundary re-resolved immediately before the mutation; full closure needs openat2 RESOLVE_BENEATH / per-component O_NOFOLLOW, tracked for the CLI/TUI rewind-wiring work).

build/vet/-race/full-suite + GOOS=windows build all green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Address #112 re-review: fail rewind on undecodable checkpoint payload

[major] restoreToSequenceLocked silently continued past a checkpoint whose payload failed to decode, which let a NEWER checkpoint win for that path and restore a later state than the caller requested. Treat corruption as a hard rewind error. Regression test TestRestoreFailsOnCorruptCheckpointPayload (fails-open before, errors now).

Re-review note: the earlier capture-target-validation (critical) and test bounds (minor) were already addressed in 600337b (resolveWithinWorkspace guard + len checks); those re-anchored threads are stale. The restore-side symlink-swap TOCTOU remains a documented heavy-lift residual (needs openat2/descriptor traversal), tracked for the rewind-wiring work.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Address #112 re-review: dedupe rewind on resolved path, not raw path

[major] restoreToSequenceLocked deduped the per-path closest-to-target short-circuit on the RAW checkpoint path, so equivalent paths (./a.txt, dir/../a.txt, a symlink alias) keyed differently and a NEWER checkpoint could overwrite the closest-to-target snapshot for the same underlying file. Now resolve/confine FIRST and dedupe on the resolved workspace path (unresolvable targets dedupe on raw path). Regression test TestRestoreDedupesEquivalentRawPaths.

This + the prior commit (24e9ba2, fail-hard on undecodable payload) address both correctness blockers @Vasanthdev2004 raised after CodeRabbit's pass.

build/vet/-race/full-suite + GOOS=windows build green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: KRATOS <kratos@KRATOSs-Mac-mini.local>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@Vasanthdev2004
Vasanthdev2004 deleted the feat/specialist-hook-events branch June 28, 2026 08:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants