Working in a repository¶
Repository instructions (AGENTS.md / CLAUDE.md)¶
The main agent and workers always load the workspace's own CLAUDE.md and
AGENTS.md. Two settings control whether they also pick up files from parent
directories and from subdirectories:
pcode config set repo_context_walk_up off # Only workspace-local files at startup
pcode config set repo_context_walk_up on # Also inherit ancestors (default)
pcode config set repo_context_nested pointer # Notify the agent of nested files
pcode config set repo_context_nested contents # Inject nested instruction contents
pcode config set repo_context_nested off # Disable nested discovery (default)
The same commands work as /config inside pcode. They are read when an agent is
created (launch, resume, or a model change), so restart pcode to apply a change
reliably. pcode config unset KEY restores the default. Turning both off still
loads the workspace's own instructions; neither setting blocks explicit file
reads or removes instructions already in a saved conversation.
Parent directories (repo_context_walk_up). For a workspace under your home
folder, the walk stops at home (inclusive); elsewhere it goes to the filesystem
root. A symlinked workspace inherits from its real location, and a .git
directory does not stop the walk. Instructions load broadest first, workspace
last, with CLAUDE.md before AGENTS.md in each directory (both load when they
differ). The startup banner lists the files loaded without printing them.
Subdirectories (repo_context_nested). After the agent reads, lists, or
greps inside a directory of the workspace, pcode checks that directory for an
instruction file. pointer adds a note telling the agent to read it if
relevant; contents adds the file's text to the conversation. Each directory is
surfaced at most once per turn, and only its first match (CLAUDE.md before
AGENTS.md) is used. Directories skipped over when jumping straight to a deeper
file are not checked, and shell commands, writes, and edits never trigger it.
This works whether or not the parent walk is on.
The agent is also told which .claude, .agents, .codex, and .grok asset
files exist in the workspace, as a list of paths only: nothing is read and no
hooks run. Discovered instructions are sent to the selected model, so review
inherited and nested files when working in a shared directory tree.
Ponytail (opt-in)¶
The bundled ponytail extension adds the ruleset from
DietrichGebert/ponytail to the
instructions: climb a ladder before writing code (does this need to exist,
does the codebase already have it, does the stdlib, does a native feature, can it
be one line) and never simplify away validation, error handling, security, or
accessibility. It ships off; /extensions on ponytail turns it on.
/ponytail lite|full|ultra|off sets the intensity, /ponytail status reports
it. lite names the lazier alternative and lets you pick, full (the default)
enforces the ladder, ultra challenges the requirement itself, and off keeps
the command but injects nothing. A change applies on the reload the command asks
for, not mid-turn.
The level is not per session. It is read from PONYTAIL_DEFAULT_MODE, then
defaultMode in $XDG_CONFIG_HOME/ponytail/config.json (or
~/.config/ponytail/config.json), the same file ponytail's plugins for other
agents use, so one level covers all of them. The command writes that file and
says so when the environment variable overrides what it just saved.
The ruleset reaches this conversation only: a delegate_task sub-agent does not
inherit it. The review, audit, and debt skills the upstream plugins ship are not
included; copy them under .agents/skills/ if you want them as
skill commands.
Skills as slash commands¶
Every SKILL.md under those asset directories becomes a command, so you can
invoke a skill deliberately instead of hoping the model notices it. A skill in
.claude/skills/cache-report/SKILL.md is named after its directory:
/skill:cache-report check the last session
The command sends a normal message asking the model to read that file and follow it, with anything you type after the command appended. It is queued like a typed message, so send mode, steering, and Ctrl+C behave as usual. The skill body is not preloaded; the model reads the file itself.
skill_dirs adds directories searched after the asset directories, so skills
can live outside the workspace:
pcode config set skill_dirs '~/.agents/skills:.agents/skills' # default
pcode config set skill_dirs '~/.agents/skills:/opt/team/skills' # share a checkout
pcode config set skill_dirs '' # asset directories only
Entries are separated by :, ~ expands to your home directory, and a relative
entry resolves against the workspace. Each directory is searched recursively.
Asset directories come first and the first skill with a given name wins, so a
workspace skill shadows a user-level one.
Naming follows skill_commands: prefix gives /skill:NAME (default), bare
gives /NAME, both registers the bare name as an alias of the prefixed one,
and off registers nothing. A bare name that collides with a built-in command is
dropped and the built-in wins. Skills are found at launch, so restart after
adding one or changing these settings. The startup banner lists the registered
commands, and each skill's frontmatter description labels it in the completion
menu.
MCP servers a skill needs¶
A skill that only works with certain MCP servers can list them under
the frontmatter's metadata (the Agent Skills spec's slot for client-specific
fields, so other assistants reading the file ignore it):
---
name: triage-incident
description: Triage an open incident from PagerDuty and Sentry.
metadata:
pcode-mcp-servers: pagerduty, sentry
---
/skill:NAME then enables each listed server that is configured in mcp.json
and not already on, exactly as /mcp enable would (including an OAuth browser
sign-in if needed), and sends the skill's prompt once they are up. A server that
fails to enable is reported and stays off while the rest proceed; Ctrl+C during
sign-in cancels the prompt too. Names missing from mcp.json get a warning.
Servers cannot change under a running turn, so invoking the skill mid-turn
prints the /mcp enable commands to run afterward instead.
This applies only to the slash command. When the model decides on its own to
read a SKILL.md, nothing is enabled.
One git worktree per session¶
Several sessions editing one checkout trample each other: one session's
git checkout or stash eats another's uncommitted edits. pcode can give each
session its own worktree and make that the workspace, so file tools, the shell,
repository instructions, and the saved session all point there. The model needs
no instructions and relative paths cannot land in the main checkout by mistake.
pcode --worktree # .worktrees/pcode-<session-id-prefix>, branch of the same name
pcode --worktree fix-thing # .worktrees/pcode-fix-thing
pcode config project set worktree on # default for this repository (committed in .pcode/)
pcode config set worktree on # default for every git repository
pcode --no-worktree # stay in the current checkout this once
The worktree lives under .worktrees/ in the main checkout (added to
.git/info/exclude, so git status stays clean without touching .gitignore)
and branches from the main checkout's current branch, reusing a branch of that
name if one exists. Session worktrees and branches are always prefixed pcode-,
so git worktree list and git branch show which ones pcode made. Starting
pcode inside an existing worktree, outside git, or with --continue never
creates another one. Resuming a session (pcode -c, or
pcode -C .worktrees/NAME -c from elsewhere) lands back in its worktree.
Git cannot install dependencies or copy untracked config, so after checkout pcode
runs two optional scripts inside the new worktree, each with PCODE_MAIN,
PCODE_WORKTREE, and PCODE_BRANCH set:
| Script | Runs |
|---|---|
~/.config/pcode/worktree-setup |
always (for what every repo needs: direnv allow, copying .envrc) |
<repo>/.pcode/worktree-setup |
only in a trusted repository (launch prompt, or project_extensions on), since it is code shipped with the repo |
An executable script runs directly (give it a shebang); anything else runs
through sh. A non-zero exit aborts the launch and removes the half-made
worktree.
Inside the session:
/worktreeshows the branch and what is unmerged./worktree mergemerges the main branch into the worktree (so conflicts are resolved there, never in the main checkout) and then fast-forwards the main branch. It works while a turn is running, so work the model already committed can land without waiting, but refuses a worktree with uncommitted changes./worktree finishmerges, then removes the worktree and its branch and quits./worktree removedeletes the directory once it is merged and clean; the branch stays./worktree listshows every worktree./worktree cleanremoves every other worktree of the repository (and its branch) with nothing uncommitted, nothing untracked, and nothing the main branch lacks. Anything else is listed with the reason it was kept, and a worktree locked withgit worktree lockis skipped. It also works from the main checkout.
Nothing is ever forced. Actions other than merge wait for a running turn to
finish. /resume can pick a session from another worktree of the repository and
move this session there; see sessions.
When a merge stops on conflicts it names the files, and /worktree resolve
hands them to the model with the branch names, asking it to resolve each so both
sides survive, run the tests, and commit the merge (never abort it). Run
/worktree merge or finish again afterwards. pcode never starts a merge or
asks the model to resolve one without you typing the command; a conflict at exit
prints the resume command and the same hint.
Workers still share the session's workspace by default, even with
worktree=on. To give each worker its own checkout, also set
worker_isolation=on (default off). Isolated tasks use task-<id> branches
starting at the parent session's current commit, not the main branch, and
/worktree list shows their owner and status. Pending tasks, and parents that
own them, are protected from removal and finish until the task's result is
integrated or explicitly discarded. Clean integrated task checkouts can be
cleaned up even before the parent merges, and a task whose setup failed keeps
its checkout for inspection. See worker worktrees.
Leaving a session tidies its own worktree (one pcode made, prefixed pcode-;
hand-made ones are only reported):
| State on exit | What happens |
|---|---|
| Untouched: clean, nothing unmerged | Removed with its branch, no question. A session that never had a turn is deleted too; otherwise it is repointed at the main checkout so pcode -c still works. |
| Committed but unmerged | worktree_exit: ask (default) prompts Merge and remove the worktree? [Y/n]; merge does it silently; keep leaves it. A merge that conflicts or cannot fast-forward keeps everything and prints how to resume. |
| Uncommitted changes | Kept, with the resume command. pcode does not commit for you at exit. |
--print has nobody to ask, so it only does the untouched cleanup. Merging
never pushes; push from the main checkout when you are ready. None of this
happens while another session is still open in the same worktree (a
copied session and its
original, for instance): the worktree is kept with a note naming that session.