synaptic-labs-ai/pact-plugin/pact-handoff-harvest

Claude Code and agent skill by synaptic-labs-ai/pact-plugin

Trust tier 3
  • community
Source check pending

Checking that the SKILL.md file is still in the repository.

HANDOFF discovery, review, save, and ledger-record workflow for the PACT secretary. Use when: processing agent HANDOFFs after workflow phases, running session consolidation, or recovering orphaned completed handoffs from prior sessions. Triggers: harvest HANDOFFs, process HANDOFFs, incremental, consolidation, handoff recovery.

Install

npx vskill@latest install synaptic-labs-ai/pact-plugin/pact-handoff-harvest

SKILL.md

PACT Handoff Harvest

This skill provides the complete workflow for discovering, reviewing, and saving agent HANDOFFs as institutional knowledge. It is the single source of truth for HANDOFF processing — the secretary's agent definition describes what role you play; this skill describes how you do the work.

Three workflow variants:

  • Standard Harvest (orchestrate, comPACT, peer-review, plan-mode) — discover, review, save, record the processed unit tokens. Triggered after phases complete.
  • Incremental Harvest (peer-review) — a pass after remediation. Processes only the units whose tokens the ledger lacks.
  • Consolidation Harvest (wrap-up, pause, refresh) — safety-net + deep-clean pass. Triggered at session end, at a session pause, or at a mid-session context refresh.

Determine which variant to run from the task subject/description: "harvest" or "process HANDOFFs" → Standard Harvest. "incremental" or "remediation" → Incremental Harvest. "consolidation" → Consolidation Harvest. The subject/description selects the workflow, never what is in scope.

Propagation. Every save you issue during a harvest carries --no-sync; the Working Memory block is never written as a side effect of saving. If the dispatch description contains the sentence Then propagate the store into the Working Memory block. — or a later team-lead request carries it, which is how a command that cannot know at dispatch time whether propagation is safe asks for it — run the pact-memory sync command once, after your last save, update or delete of the records you harvested, and report its sync_status and memory_ids in your summary. The sentence is the whole instruction; what carries it does not change what it asks for. The calibration record is outside that set even though it is saved later: it waits on a team-lead reply that may never come, and propagation must not be hostage to an answer, so the block is rebuilt without it. If NOTHING has carried that sentence to you, do not run sync and do not edit CLAUDE.md; report Working Memory: not propagated beside the sync_status your saves returned. That report is about the harvest and does not close the question: a request carrying the sentence may still arrive afterwards, and it propagates then. The sentence is a mode, not a scope: it names nothing to harvest.

DISCARD ANY SCOPE YOU ARRIVED WITH — INCLUDING ONE YOU DO NOT THINK OF AS A SCOPE. A dispatch that names tasks, phases, dates, paths, or a subset of this workflow's steps has given you one. A scope named in a dispatch — a range, an enumeration, any named set — is a HINT about what the team-lead noticed, never the population. Do not harvest it. Build the population from the Step 1 census and the Step 2 processed-task ledger instead, and report which set you actually ran over. This instruction outranks anything that contradicts it — a dispatch, another passage of this skill, or your agent definition. Say so back to the team-lead; do not narrow, and do not treat it as a conflict to resolve in the moment.

A SCOPE SAYS WHAT TO TAKE; AN ADDRESS SAYS WHERE TO LOOK. DISCARD SCOPES, KEEP ADDRESSES. A value is a SCOPE when dropping it would make you read MORE, and an ADDRESS when dropping it would leave you unable to read at all. Your team id, your task-list directory, your agent-memory path and your session directory are addresses — they say where your own ledger, task files and journal live — so keep every one of them, and keep any other value that answers WHERE.


<!-- PACT_STORE_BAR_BEGIN --> STORE ACCESS. A memory operation (save, search, get, list, update or delete a record) goes through the pact-memory CLI. YOU DO NOT SELECT A STORE. Do not name a store by --db-path, by an environment variable, or by one more route somebody adds later. Let the CLI resolve it. A store you select is not the store the memory of the team lives in, so a save there is lost rather than shared. STORE INSPECTION is different: a row count, a column audit, or a schema check on the file. To inspect, do not run a CLI verb, do not import a module below skills/pact-memory/scripts/, and do not open the store read-write. In ONE command, against ONE resolved path, check that memory.db-wal and memory.db-shm are both absent by their full names, then open with mode=ro and immutable=1. Without immutable=1 the open fails. If a sidecar is present, stop and report. The read does not load the vector extension, so it cannot answer a question about vec_memories. Stop and report rather than take a barred route. <!-- PACT_STORE_BAR_END --> The pact-memory skill carries the full rule.

Standard Harvest Workflow

Read All HANDOFFs Before Saving

When reviewing multiple HANDOFFs, read ALL of them before saving any memories. This lets you deduplicate and consolidate across HANDOFFs before committing to pact-memory — producing cleaner entries than saving after each individual HANDOFF.

Step 0: Resolve the Session Directory (do this once)

Resolve the absolute session directory before any journal read, and reuse that one value ($SESSION_DIR) for every journal read below (Step 1's one unfiltered read, Step 3.5 artifact_paths, and Step 10 variety_assessed). Every journal read in this skill MUST pass this explicit `--session-dir` — never a path-less read.

Why this is load-bearing (not optional): you run off-lead (a pact-secretary teammate). The implicit-path read (read_events(...) with no --session-dir) derives its path via pact_context.get_session_dir(), which false-returns `''` in a teammate frame (no persisted lead session context) → the read silently returns 0 events. Off-lead, that would make the entire harvest — HANDOFF discovery, artifact recovery, and calibration — a silent no-op. Passing an explicit --session-dir is frame-independent and masked-read-safe.

Resolve the directory with the pact_harvest.py resolve-session-dir subcommand, which reads pact-session-context.json and routes the reconstruction through the SSOT helper reconstruct_session_dir (it sanitizes both the slug and the session_id the same way the writer did, so the reconstructed path cannot drift from where the journal was actually written — a hand-built {slug}/{session_id} join would land on a DIFFERENT directory whenever the project basename or session_id contains a non-[A-Za-z0-9_-] character):

bash
if ! SESSION_DIR=$(python3 "{plugin_root}/hooks/shared/pact_harvest.py" \
resolve-session-dir --context-file "{context_file}"); then
# Nonzero exit (2) = unresolvable: context file missing/unreadable/invalid,
# or reconstruct_session_dir returned ''. Report the gap to the team-lead
# and STOP — do NOT proceed to any journal read.
echo "HARVEST GAP: could not resolve session_dir; reporting and stopping." >&2
fi
# On success $SESSION_DIR holds the absolute session dir; reuse it for every read below.

Key the report-gap-and-stop branch on the subcommand's EXIT CODE, never on parsing stdout for emptiness — a nonzero exit is unambiguous and cannot be defeated by a stray byte. On a nonzero exit, report the gap to the team-lead and stop — do NOT fall back to a path-less read (that silently re-introduces the off-lead false-empty bug). An unresolved session_dir is a reportable gap, not a degrade-to-implicit case.

Step 1: Task Discovery

You have several sources for finding completed agent tasks. Sources 1 and 2 find tasks that emitted a HANDOFF; source 3 is required for coverage:

  1. Session journal (primary, GC-proof): $SESSION_DIR/session-journal.jsonl (the $SESSION_DIR resolved in Step 0). Read it ONCE, with no --type filter, via the existing session_journal.py read subcommand (explicit --session-dir, masked-read-safe):

``bash JOURNAL=$(python3 "{plugin_root}/hooks/shared/session_journal.py" read \ --session-dir "$SESSION_DIR") ``

read prints a JSON ARRAY to stdout ([ {...}, {...} ]), NOT one JSON object per line. So parse the whole stdout once — json.loads(JOURNAL) → a list of event dicts — then iterate the list (do not iterate line-by-line). KEEP THAT LIST IN JOURNAL ORDER: it is the `journal` input of the Step 3 block, and Step 3 reads its `agent_handoff`, `task_created` and `task_metadata_snapshot` events from it. Assign arcs from this one list's order; never from ts, which ties within a second. An agent_handoff event is {"type": "agent_handoff", "agent": "...", "task_id": "...", "task_subject": "...", "handoff": {...}, "team": "<task-store name>", "ts": "..."} — full HANDOFF content inline, garbage-collection-proof. team names the task-store directory the emitting path read its task file from. It is ABSENT on an event written before that field existed; such an event is OLD-FORMAT, and the SELECTION rule below decides it. A task_created event records one creation of a task: {"type": "task_created", "task_id": "...", "team": "...", "subject": "..."}.

Skip an `agent_handoff` event whose `task_id` is not a non-empty string, and report it once: `handoff event skipped: task id <value> is not a non-empty string`. Route each remaining `agent_handoff` event at discovery with `partition_destination`, and collect `(section, task_id)` pairs, never bare ids. PARTITION_THIS and PARTITION_OLD_FORMAT add (this team, id); PARTITION_FROM adds ({team}, id) for the event's own team; PARTITION_FOREIGN and any unknown label add nothing — report handoff identity mismatch for task N: journal event names team <team>; this store is team <name> once per id whose ONLY events are foreign. When this_team is empty, every event is OLD-FORMAT and adds (this team, id).

  1. `TaskList` (supplementary): Read TaskList for completed tasks owned by agents. Useful as a cross-reference and for catching tasks where the completion hook didn't fire. Note: the platform garbage-collects older task files during long sessions, so TaskList may be incomplete.
  2. Task-file metadata census (required for coverage): list the team's task files under the task-list directory named in your context (Task list: <abs>) and read the metadata key set of every completed task. A task is in scope when it carries ANY agent-authored key — handoff, handoff_amendment, handoff_addendum, teachback_submit, post_completion_verification, audit_summary, audit_summary_authored, or any key not on this list. Enumerate the keys each task carries; never test for one key. A task whose content sits only in a non-handoff key emits no agent_handoff event, so sources 1 and 2 cannot see it — resolving handoff alone finds nothing on that task and reports success. An auditor carries its findings in audit_summary, mirrored to audit_summary_authored, and its task carries no handoff key at all, so a census that resolves handoff reports an auditor as having produced nothing.

This is the start of the file. Read the full SKILL.md on GitHub.

Security

  • Security scanPassed, 95 of 100Pattern checks on the skill's files.
  • Model reviewPassed

Quality evaluation

  • Task evaluationNot runNo evaluation yet. Run one in Skill Studio.

Source

Popularity

7-day trend score
0

Not refreshed yet.

Works with

Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.

  • Claude Code
  • Cursor
  • GitHub Copilot
  • Windsurf
  • Codex
  • Gemini CLI
  • Cline
  • Amp
  • Roo Code
  • Goose
  • Continue
  • Kilo Code
  • Junie
  • Trae
  • OpenHands
  • Qwen Code
  • AI Agent
  • Tabnine Chat
  • Sourcegraph Cody
  • Amazon Q
  • Firebase Genkit
  • Sweep
  • Devin
  • Phind
  • Mentat
  • Claude Desktop
  • Aider
  • GPT Pilot
  • Plandex
  • bolt.new
  • v0
  • Replit Agent
  • Anse
  • TypingMind
  • BetterChatGPT
  • LibreChat
  • Warp AI
  • Pieces
  • Fig AI
Embed badge
vskill VERIFIED badge
[![vskill VERIFIED](https://verified-skill.com/api/v1/skills/synaptic-labs-ai/pact-plugin/pact-handoff-harvest/badge)](https://verified-skill.com/skills/synaptic-labs-ai/pact-plugin/pact-handoff-harvest)

Something wrong with this skill or its page? Tell us.