pstack-harness
Maps pstack's delegation and portable resource primitives to the current CLI (Claude Code, Codex, Hermes, Grok Build, or any other harness). Covers how to locate installed skills and fresh trunk resources, spawn a subagent, set a per-subagent model, parallelize arms, go read-only, ask a structured question (AskQuestion), track a worklist, loop, and locate the transcript store. Read whenever a pstack skill says spawn, Task tool, subagent_type, per-subagent model, AskQuestion, or worklist, names a sibling skill you cannot find, or runs a path from a playbook. Every primitive is named differently per harness, so read this before concluding your harness has no such capability or resource.
How do I install this agent skill?
npx skills add https://github.com/mdsmithaustin/pstack --skill pstack-harnessIs this agent skill safe to install?
- Gen Agent Trust Hubpass
The skill facilitates subagent delegation, resource mapping, and task tracking across several AI harnesses (Claude Code, Codex, Hermes, Grok Build). It performs operations such as cloning the author's own repository for updates, managing worktrees for isolation, and registering subagent configurations in the harness's local settings. Security risks include an indirect prompt injection surface from processing external data and potential exposure of sensitive historical session transcripts.
- Socketwarn
1 alert: gptAnomaly
- Snykpass
Risk: LOW · No issues
What does this agent skill do?
Harness adapters
pstack skills describe delegation abstractly: "spawn a subagent on model X", "launch N in parallel in one message", "readonly", "AskQuestion". Each is an intent, not a tool name. Satisfy the intent with whatever your session actually provides. Your live tool inventory and your CLI's own help are the authority, not this file. Never invent a tool. Say which mechanism you used when it affects execution or evidence. For worklists, report the item state rather than the carrier.
Resolve portable resources
When a pstack workflow uses a PSTACK_SKILLS_ROOT, PSTACK_SOURCE_ROOT, or PROJECT_ROOT command, read the portable resource path contract in full. These commands run bundled scripts, address installed resources, read fresh pstack trunk, or read a consumer control skill. Resolve only the roots that the next command needs. Keep the exact command forms in generated plans and restore the recorded roots across owners, delegates, wake-ups, and later ticks.
Preserve roles across handoffs
Carry delegation roles into plans, checkpoints, and handoffs. Record the resolved harness, model, and effort as execution observations. Preserve a specific-model override with its original explicit human request. Model names in defaults, examples, past runs, or agent-written summaries do not establish such a request. If the source is unavailable, report the uncertainty instead of attributing the model choice to the human. A direct human model request still takes precedence.
For durable recovery, preserve the exact role and one-based panel arm, brief, standing orders, checkout, resolved identity, and any observed native task id or CLI receipt. A missing observation leaves the child's liveness unknown. It does not prove that the child stopped. To recover, spawn the saved role per Spawn a role like any other spawn, and use the printed arm whose arm matches the saved arm. Do not choose default, another panel arm, or a guessed model. Record the harness, model, and effort that the replacement runs on. Recovery keeps the workflow's existing retry allowance.
Retain the exact raw --work-model argument from the final successful resolver invocation and its complete printed arm. Keep this pair separate from observed execution identity. In an orch attempt, save it as resolutionContext: {workModel, resolvedArm} per the orch reference. A successful invocation without the flag records workModel: null. An unsuccessful resolver invocation supplies no successful context. Keep legacy absence unknown. Later model substitution or effort inheritance does not rewrite the saved arm. To recover a trail reviewer, pass a saved string workModel as --work-model. For a saved null, omit the flag. Without saved context, pass the model the work ran on, as for a new review.
Spawn a role
Every pstack spawn runs a role from the models config, such as feature or how explorer, sometimes under a persona. Build each spawn in this order.
-
Name the role and the persona. The skill or playbook step names the role. A spawn whose skill names no role uses
default. Asubagent_typeofpoteto-agentorcomment-sickoin skill text names a persona, andgeneral-purposenames none. Neither one picks the model or the effort. -
Resolve the role. Run the resolver once per task, and again after the harness or config changes:
python3 "${PSTACK_SKILLS_ROOT:?}/setup-pstack/scripts/check-models-config.py" --resolve --harness <claude-code|codex|grok|hermes> [--work-model <model>@<effort>] [<role>...]Failure signal: nonzero exit. It prints one JSON line per arm with
model,effort, andsource, and anoteslist when the resolver has a warning. Relay each note to the user in the reply. Pass the roles the skill names, or none to print every role. Run it from the project root or pass--project <root>. Do not read the config files to pick values. The rules, and the grammar for editing the files, live in setup-pstack's models config reference. When you resolvetrail reviewer, pass--work-model <model>@<effort>with the model and effort that did the work, and use the printed arm. When the work's role resolved toinherit-parent, pass the session model. Pass the model the work ran on, as the role's resolved value or the CLI's own model ID. A full Claude ID such asclaude-opus-5-5maps to its alias on a CLI that takes aliases, and stays a literal slug on Hermes. On Claude Code, a work model that is not a Claude alias or ID exits 2. On another CLI, a work model that CLI cannot use adds a note and applies no step. When the exit 2 names--work-model, correct a Claude value, such as dropping a[1m]suffix from an alias, and rerun. If the work ran on another vendor's model, rerun without the flag: every Claude Code arm is a Claude model, so the printed arm is cross-model. Otherwise rerun without the flag and say in the verdict and the reply that it may be a same-model review. The resolver prefers a different model in the work model's family that the user's config allows, a higher tier first, and adjusts the effort. A"step": "same-model"field means the config allows no other model in the work model's family, so the verdict and the reply say it is a same-model review. Every model you pass comes from this output or an explicit request in the task. Never improvise one, and say which role each model came from. If the resolver exits nonzero or cannot run, still spawn the role. Omit the model and effort so the child inherits the session's. Fortrail reviewer, the verdict and the reply then say it may be a same-model review. For a panel role, keep the arm count that the panel's skill names as its default, and brief each arm the way that skill says. Report the resolver error and the values the child ran on. Never drop a spawn because the resolver failed. -
Build the spawn call for this CLI, through the mechanism in Spawn a subagent below.
inherit-parentin a field means omit that field.-
Claude Code. Pass
model. The spawn tool has no effort field, so the agent type carries the effort. Eachpstack-effort-<level>agent runs at its level and takes themodelyou pass.resolved effort no persona a pstack persona a level, and pstack-effort-<level>is in the live agent catalogpstack-effort-<level>pstack-effort-<level>, with the persona's complete briefing at the top of the prompta level, but that agent is not in the catalog general-purposethe persona per the persona contract inherit-parentgeneral-purposethe persona per the persona contract Only the live catalog proves an agent is loaded. A file on disk does not. A delegate's own spawns inherit the delegate's effort, so a nested spawn with an
inherit-parenteffort runs at the delegate's level, not the top session's. -
Codex. Pass
modelandreasoning_effortonspawn_agent, and whenever you pass either, setfork_turnsto"none", or to a positive integer to carry the last few turns. A full-history fork, withfork_turnsomitted or"all", inherits the parent's model and effort and ignores overrides. So a role that resolves to a model or an effort never forks the full history. Only a role that resolves toinherit-parentfor both may. Setagent_typeto the persona's native name when the live agent catalog lists it, and otherwise todefaultwith the persona's briefing at the top of the message. Whenspawn_agentshows noagent_typeparameter, this session loaded no custom agents, so omit the field and put the persona's briefing at the top of the message. -
Hermes. Pass the values through the delegation toolset's fields when it has them, or as
--reasoningonhermes -z. -
Grok Build. Resolve with
--harness grok. Passmodelonly whenspawn_subagentlists the argument. With subagent model inheritance on and an all-xAI catalog, Grok hides it and rejects a spawn that names one, so the arm runs on the parent model. The spawn takes no effort, so a resolved level runs at the session effort and step 5 reports it. -
Forks. A fork, such as Claude Code's
forkagent type or a Codex full-history fork, inherits the lead's whole context and runs on the lead's model and effort, ignoring any override. Fork only when the role resolves toinherit-parentfor both, asdefaultships, and the brief would otherwise restate context the lead already holds, such as drafting from files the lead just read or writing a resume note. Never fork a verdict, a review, or a role that resolves to a model or an effort. A fork returns the same thin report as any spawn, per principle-guard-the-context-window.
-
-
Brief the persona. A persona that runs as a briefing gets its complete text from the persona contract. Never summarize it.
-
Fall back without dropping an arm. If the spawn rejects a model, or a spawned arm fails on model availability such as exhausted usage credits, omit the model, let the arm inherit the session model, and report the substitution. When the fallback model is the work model, label that arm's verdict a same-model review. For explicitly requested models, use the arena skill's required-arm rule. If no field or agent can carry the effort, the effort alone becomes
inherit-parent. Keep the model and the arm. Say in the reply which role's effort was inherited and why, such as "how explainerran at the session effort becausepstack-effort-xhighis not loaded. Run/setup-pstackto register it." When a persona ran as a briefing in an effort agent's prompt instead of under its native name, say that too.
The primitives
Spawn a subagent. In order of preference:
- Your harness's native subagent or delegation tool, whatever it is called.
- No such tool → invoke your own CLI non-interactively as a subprocess (its help names the command and flags), one invocation per arm, run concurrently in background shells, each arm's report collected from stdout or a file path named in its brief.
- No subprocesses either → run the arms sequentially inline, one at a time, each writing its report to a file before the next starts, then synthesize. Keep the configured arm count. A verdict or review that runs inline is not independent. Label it
self-reviewin the verdict and in the reply, and never count it as an independent verdict.
Each writer gets its own git worktree, whichever mechanism spawns it. Keep the location a native isolation option picks when the option makes a git worktree, that is, when git -C <its path> rev-parse --path-format=absolute --git-common-dir prints the project's. Grok Build's isolation: worktree can make a standalone clone instead, so a writer there that needs a git worktree gets one from git worktree add. On Grok Build, spawn every writer with isolation: none, because a Grok role or persona default turns isolation on when the field is omitted. Pass the writer's directory as cwd when spawn_subagent lists that argument. When you run git worktree add yourself, make one worktree at a time, and never place the worktree beside the repository:
- A throwaway checkout (verify, review, replay, eval arm) goes under
mktemp -d "${TMPDIR:-/tmp}/pstack-<slug>.XXXXXX". Remove it withgit worktree removewhen its run ends. - A worktree that holds unpushed work goes under
.worktrees/<slug>in the main checkout. If the repository does not ignore.worktrees/, append it to"$(git rev-parse --git-common-dir)/info/exclude"first.
If git worktree add fails, give each writer whose output the lead collects from a directory, such as an arena candidate or a verify arm, its own plain directory for each commit its brief names, or one directory when the brief names none. A verify arm whose brief names a parent and a head gets two. Use the directory its skill names, or a fresh mktemp -d "${TMPDIR:-/tmp}/pstack-<slug>.XXXXXX" for each. When the writer needs the project's files, resolve every named commit, or HEAD when the brief names none, with git -C <project> rev-parse --verify -q "<commit>^{commit}" before you seed any directory. If it prints nothing, run git -C <project> fetch origin <commit> and resolve again. If the commit is still missing, report the writer blocked and seed none of its directories. Never seed a different commit in its place. Otherwise seed each directory with git clone -q --no-checkout --shared <project> <dir> && git -C <dir> checkout -q --detach <sha>, where <sha> is what its own commit resolved to. Its brief names each directory and its SHA, says to work only in those directories, and says to leave the checkout unchanged. These writers can run at the same time. Delete each directory when its run ends, after you take its output. A writer whose work must land on the checkout's branch runs in the current checkout, one at a time. Codex's workspace-write sandbox keeps .git read-only, so git worktree add fails there. Never take the writer's work back into the lead.
Parallelism. Real where the mechanism allows it (independent tool calls in one message, concurrent subprocesses); otherwise sequential with the same arm count.
Read-only. Use an enforcing option if the spawn mechanism has one; otherwise state it plainly in the brief ("read-only: do not edit or write files").
Structured questions (AskQuestion). Your harness's structured-question tool if it has one; otherwise ask in plain chat.
Track a worklist. The worklist is an ordered collection of items with pending, in progress, completed, or skipped: <reason> state. State the complete initial list before starting, keep at most one item in progress, and update it when an item changes state or the list changes.
Choose its carrier by capability, never by a remembered product-specific name:
- Inspect the tools and channels already exposed in the live session. Prefer a native structured capability whose description says it creates or updates task, plan, or work-item state.
- If the harness supports deferred capability discovery, make one semantic query for a capability that tracks ordered multi-step work and item status. Do not query product-specific names.
- If structured tracking is available, use it. If discovery finds none or any call is rejected, stop trying that carrier for the rest of the task. Publish and maintain the same worklist through the harness's normal progress-update channel. Both are native carriers of the same contract. On that channel, post the worklist as a numbered list with each item's state, and re-post it when an item changes state or the list changes.
Do not create a scratch task file solely because structured tracking is unavailable. A durable file is appropriate only when the workflow must resume across sessions; use that workflow's named state or decision-trail artifact. Ordinary capability variation needs no warning, apology, or "fallback" announcement. Report the current worklist, not the plumbing that carries it.
Loops and wake-ups. Your harness's loop or scheduling facility; otherwise a re-invoking wrapper (script, cron, CI). If neither exists, end each reply with the next tick's due time and its checklist, run that tick on the next turn, and report that the cadence is manual. Never skip a tick silently.
Transcripts. Every harness keeps this workspace's session record somewhere — log files under its data directory, or a database with an export command. Locate yours before reading, and stay inside the current workspace's sessions; other projects' transcripts are private.
Hints for known harnesses
Observed circa 2026-09. Treat as starting points, not contracts — verify against your live session before relying on any of them, and prefer what you find over what is written here.
| harness | spawn | worklist carrier | effort | transcripts |
|---|---|---|---|---|
| Claude Code | Task tool (custom agents from .claude/agents/ spawn by name); model takes short aliases | Prefer any exposed structured task-tracking capability; otherwise use normal progress updates. When the task tools are off, setup-pstack step 0b names the switch. With tool search on, the default, they arrive deferred, so the discovery step in Track a worklist applies | no per-call field; a pstack-effort-<level> agent type carries it (see Spawn a role). An inherit-parent effort, or a session whose catalog lacks the agent, runs at the session effort (--effort, effortLevel) | JSONL under ~/.claude/projects/<slug>/, <slug> = the resolved workspace path with every character other than a letter or digit turned into - |
| Codex | spawn_agent (the multi-agent feature, stable in 0.152) takes a model and a reasoning effort per spawn, with the fork_turns rule in Spawn a role; custom agents use TOML in ~/.codex/agents/ or .codex/agents/ with name, description, and developer_instructions; generated pstack personas leave model and effort unset; codex exec is the subprocess route | Prefer any exposed structured plan-tracking capability; otherwise use normal progress updates in the commentary channel. Goal lifecycle tools are not work tracking unless the user explicitly asked to create a goal. When the plan tool is off, setup-pstack step 0b names the switch | the reasoning-effort field on spawn_agent; -c model_reasoning_effort=<value> on codex exec. A model set without an effort gets that model's default effort (low on gpt-6.1-sol, medium on the other gpt-6 models), not the parent's, so always pass one | JSONL under ~/.codex/sessions/ by date |
| Hermes | a delegation toolset when enabled; hermes -z for one-shot subprocess runs | Prefer any exposed structured task-planning capability; otherwise use normal progress updates | --reasoning <value> on hermes -z; config agent.reasoning_effort and per-model agent.reasoning_overrides. Whether the delegation toolset takes an effort field is unverified: check its schema in session | SQLite store; hermes sessions subcommands list and export |
| Grok Build | spawn_subagent. On 1.0.41 its schema has no agent type and no argument names a persona, so pass a pstack persona's full briefing in prompt, prefix description with that persona's name in brackets, such as [poteto-agent] or [comment-sicko], so the subagent label shows it, and on resume_from keep the tag but skip the briefing because the child already has it. Grok loads the ~/.claude/agents/ wrappers as agent types, and its source honors a subagent_type key that arrives, but the schema hides the key and a model told to send it dropped it in a 2026-09 probe, so do not rely on naming the type. A model argument appears unless subagent model inheritance is on (default off, settable remotely) and every catalog model is xAI. Only the top-level session spawns, so a delegate cannot fan out. Per Grok 1.0.52's docs, isolation: worktree makes a copy under ~/.grok/worktrees/ whose kind follows cli.worktree_type (linked, standalone, or git, and Grok can set it remotely) and the Grove settings, and a spawn that omits isolation takes a role or persona default. For a standalone clone, git worktree list omits it and git worktree remove refuses it. Remove a stray copy with grok worktree rm --dry-run <path>, then grok worktree rm <path>, which keeps a copy with unsaved work unless you pass -f. grok worktree gc --max-age <age> also keeps such a copy. Spawn a subagent says when to pass isolation: none and cwd. grok -p is the subprocess route | Prefer any exposed structured task-tracking capability; otherwise use normal progress updates | no per-spawn field; reasoning_effort on a Grok role or persona, otherwise the session effort, so the effort is inherit-parent here. --effort <value> on grok -p | per-session directories under ~/.grok/sessions/<url-encoded cwd>/<session>/; each spawn records subagents/<id>/meta.json |
Codex agent cap. Codex caps subagents, and a spawn past the cap fails with agent thread limit reached and creates nothing. If your tools include close_agent, by default at most 6 agents stay open per session and a finished agent holds its slot until closed, so launch at most 6 at once and close each agent once you have read its result. If they do not, by default at most 3 subagents run at once and finished ones free their slots, so launch parallel arms in waves of 3 or fewer. Either limit overrides a skill's "spawn all in one message". The arm count stays the same either way. After a limit error, never wait for the refused arm: spawn it when a slot frees. Run it yourself only when the arm needs no other model, and report it as a substitution. Without close_agent, wait_agent takes no target and blocks until its timeout when no child is running, so call it only while a spawned child is still working. Name each child's scope in its brief: the question and the files or areas it owns. Do not read or search a scope that a running child owns, unless a skill step says that read runs in parallel with the child, as arena's Phase C says of the Phase D read. When a new fact changes a child's question, send the fact to that child. Wait with wait_agent when each remaining task belongs either to a running child or to an arm that waits for a free slot. Spawn each waiting arm as soon as a slot frees. After a child reports, spot-check its claims.
Universal rules
- Panels keep their configured arm count. Run a three-model panel as three arms even in a one-model harness. Brief each arm the way the panel's skill says, and run the arms in parallel or sequentially. For exact model requests, apply the required-arm rule above.
- Use named sibling skills yourself. "Use the architect skill" tells you to load the pstack skill
architectand follow it. The name is a sibling directory under the installed skills root, the directory that holds this skill's own directory. Any other pstack mention of a skill by name, such as "the leaf skill", names one the same way. On Claude Code, call the Skill tool with the bare name, such asarchitect. The call works when the listing shows the name only, with no description, and a name-only listing never means the skill is missing. On Codex, Grok Build, Hermes, and any other harness, read<installed skills root>/<name>/SKILL.mdin full, then read the files it references when its steps need them. Never ask the user to type a skill that a pstack skill names. Never edit a skill's files or the listing settings to change how it loads. - Load only skills that someone named. Never read or load a pstack skill that you found by listing or searching a skills directory, unless the user or a loaded skill named it. A skill that the harness lists with its description can still load from that description.
- Tool names in skill text describe intent, never a required tool.
Task,Glob,Grep,Read, a worklist, and Cursor-era parameters likereadonlyname capabilities: realize each with whatever your session provides (a search tool, a shell command, a read-only brief). Capability selection follows live descriptions, not recalled names. A missing optional tool never cancels the step and needs no announcement. Asubagent_typein skill text names a persona or none, and Spawn a role turns it into the concrete type. - Honesty: never report parallel arms that actually ran sequentially; name the mechanism used. Wherever a rule labels a review same-model or
self-review, put the label in the verdict and in the reply.
How can the creator link this skill?
Add the canonical catalog link to the repository README so users can inspect current installs and available audits. The publishing guide covers the complete discovery path.
<a href="https://skillzs.dev/skills/mdsmithaustin/pstack/pstack-harness">View pstack-harness on skillZs</a>