# pi-anchored-standard

[DeepSeek Harness "Anchored Standard"](https://github.com/xiaobright/dsh-anchored-standard)
as a [pi](https://pi.dev) package.

The DSH community finding: DeepSeek-V4-Pro's agent trajectory is decided by
what the model sees on the **first request** — the Minimal preset's system
prompt + its exact two-tool schema. Anchored Standard reproduces that first
request, then widens the catalog after the first tool call. This package does
the same thing inside pi, so you can run V4 Pro through pi (with pi's
extensions, skills, subagents, web access…) without giving up the anchor.

Not affiliated with DeepSeek or with the upstream author. Experimental.

## What it does

| Request | System prompt | Tool catalog |
|---|---|---|
| #1 (bootstrap) | `You are a helpful software engineer assistant.` | `bash` (persistent) + `str_replace_editor` — **byte-identical** to DSH Minimal (name, description, JSON schema, key order; verified against a captured DSH `request/header`) |
| after first tool call / reply (promoted) | same | bootstrap pair + `dev_tool_search`, `skill_search`, `skill_load` + whatever the model unlocked |
| after a compaction (controlled) | same | bootstrap pair + `compactionTools` (default `read write edit grep find ls`) until a new promotion signal |

Also, while engaged:

- no AGENTS.md digest, no skill catalog, no tool guidance, no pi identity in
  the system prompt — ever (DSH `persona.complete: true`);
- after promotion, ONE short user-role hint says which instruction files exist
  (AGENTS.md etc.) so the model reads them itself (DSH `instruction-hint`);
- every other installed pi tool (built-ins, web access, subagents, ask-user…)
  is discoverable/unlockable via `dev_tool_search`; unlocks persist for the
  session and survive resume/reload/compaction;
- `max_tokens` is pinned to 256000 (DSH's official adapter default — the
  measured anchor condition; pi would send 384000) and `strict` is stripped
  from the serialized function tools (DSH sends none);
- the phase is derived from the session branch, so `/resume`, `/fork`,
  reload and compaction keep it.

`bash` is a real persistent shell (cwd/env/functions survive across calls,
stderr merged, 300 s timeout → partial output + reset, `[exit code: N]` marker,
16000-char clip with DSH's `<response clipped>` note). `str_replace_editor` is
a straight port of DSH's editor (`view` / `create` / `str_replace` / `insert`,
absolute paths, same messages).

## Install

```sh
pi install npm:pi-anchored-standard                           # recommended
pi install git:github.com/Shiro-Legacy/pi-anchored-standard   # GitHub
pi install /absolute/path/to/pi-anchored-standard             # local checkout
```

Then run pi on DeepSeek:

```sh
pi --provider deepseek --model deepseek-v4-pro --thinking high
```

Auth: `DEEPSEEK_API_KEY` in the environment, or `/login` inside pi.

### Provider gate

By default the anchor engages **only when the session's provider is
`deepseek`**; on any other provider the extension stays passive (pi's normal
prompt and tools), so one global install does not hijack your GPT/Claude/Grok
sessions. Override with `--anchored` (force on for this session) or
`"providers": ["*"]` in the config.

Note: activation registers a `bash` tool that overrides pi's built-in `bash`
for the rest of that process; if you switch models mid-session to a
non-listed provider the extension goes passive but the persistent shell stays.
Start a fresh pi for other providers.

## Configure

Optional JSON, later wins: `~/.pi/agent/anchored-standard.json`,
`<cwd>/.pi/anchored-standard.json`, env `PI_ANCHORED_STANDARD='{...}'`.

```jsonc
{
  "providers": ["deepseek"],           // "*" = all
  "persona": "You are a helpful software engineer assistant.",
  "bootstrapTools": ["bash", "str_replace_editor"],
  "residentTools": ["dev_tool_search", "skill_search", "skill_load"],
  "compactionTools": ["read", "write", "edit", "grep", "find", "ls"],
  "promoteOn": "either",               // "tool-call" | "assistant-message" | "either"
  "appendSystemPrompt": "message",     // what to do with --append-system-prompt:
                                       //   "message" = user-role message after the first prompt (default)
                                       //   "system"  = append to persona (breaks the byte-identical anchor)
                                       //   "drop"
  "maxTokens": 256000,                 // null = leave pi's value
  "stripStrictFromTools": true,
  "instructionHint": true,
  "shellTimeoutMs": 300000,
  "maxOutputChars": 16000,
  "bashPath": "bash",
  "notify": true                       // TUI notices on phase changes
}
```

`/anchored` inside pi prints the current phase, catalog, unlocks and config.

## Verify

`PI_ANCHORED_TRACE=/path/trace.jsonl pi …` appends one JSON line per provider
request (system prompt, tool names, `max_tokens`, full tool schemas) — the pi
analogue of DSH's `request/header` events. For request #1 you should see:

```json
{"seq":1,"phase":"bootstrap","model":"deepseek-v4-pro","max_tokens":256000,
 "system":"You are a helpful software engineer assistant.",
 "tools":["bash","str_replace_editor"],"messageCount":2, ...}
```

and from #2 on `"phase":"promoted"` with the resident set. `npm test` runs the
unit tests, including a byte-for-byte comparison of the two tool schemas
against the captured DSH header (`test/fixtures-dsh-minimal-header.json`).

## Differences from the DSH preset

- DSH's `bash` rides a PTY; this one drives `bash` over pipes with the same
  marker protocol (`exec 2>&1`, per-command stdin `/dev/null`, `set +H`).
  Interactive/TTY-dependent programs behave differently. The model-facing
  schema and description are identical.
- DSH strips two specific injected messages on request #1; pi builds those
  into the system prompt instead, so replacing the system prompt achieves the
  same "only the user message + persona" first request.
- `skill_load` returns the skill body as the tool result rather than injecting
  it into the next request.
- Post-promotion tools come from whatever is installed in *your* pi, so the
  `dev_tool_search` index text is generic; an empty query lists the catalog.
- No Windows `custom-bash`; needs a `bash` on PATH.

## Layout

```
extensions/
  index.ts                    package entry point
  anchored-standard/
    index.ts                  extension: gate, tools, phase wiring, provider hooks, /anchored
    schemas.ts                byte-identical persona + tool descriptions/schemas
    persistent-shell.ts       persistent bash over pipes
    editor.ts                 str_replace_editor port
    phase.ts                  bootstrap → promoted → (compaction) → controlled machine
    config.ts                 config layers + validation
test/                         node --test (Node ≥ 22.18, type-stripping)
```

## Credits

Mechanism, measurements and the original DSH preset:
[xiaobright/dsh-anchored-standard](https://github.com/xiaobright/dsh-anchored-standard)
and [xiaobright/modeltest](https://github.com/xiaobright/modeltest). MIT.
