# Usage Guide

## Requirements

- Node project using `@earendil-works/pi-coding-agent`
- Sage CLI installed and on `PATH` (`sage`)
- See [earendil-works/pi](https://github.com/earendil-works/pi) and [sage-protocol/sage](https://github.com/sage-protocol/sage)

## Integration Modes

1. **Pi CLI extension** — `pi install npm:@sage-protocol/pi-adapter` (no source changes)
2. **SDK embedding** — `createSageSessionConfig(...)` for harness source owners

## Pi CLI Mode

```bash
pi install npm:@sage-protocol/pi-adapter
pi list  # verify installed
```

Restart Pi and use it normally. The packaged extension provides:

- SessionStart Sage context, loaded inventory, MCP tools, and behaviors
- Pi-native skill discovery through `<available_skills>` and `/skill:<name>`
- prompt/response capture through `sage capture hook prompt/response`
- observation of complete native `SKILL.md` reads and full `skills.get` loads
- source- and session-qualified load receipts
- `sage_mark_guided_use` for binding applied loaded skills to the exact prompt capture
- optional pre/post-tool security scanning
- explicit skill resolution for subagents that do not inherit Pi's native skill catalog

The extension does not run `sage suggest hook skill` per prompt and does not
inject `sage-suggested-skills`. It also has no suggestion auto-skip,
auto-reject, or suggestion-quality widget lifecycle.

## Native Skill Workflow

1. Choose from Pi's native `<available_skills>` catalog.
2. Load the selected skill with `/skill:<name>` or a complete `SKILL.md` read.
3. Follow the loaded procedure.
4. If at least one instruction, constraint, or output structure from it guided
   the current turn, call:

   ```text
   sage_mark_guided_use({ skills: ["<loaded-key>"] })
   ```

The adapter observes successful complete loads, writes a load receipt qualified
by Sage source and Pi session, and lets the daemon bind guided use to the exact
active prompt capture. Partial reads, unloaded keys, ambiguous bare names,
missing captures, and failed receipt/feedback writes fail closed. Loading a
procedure without applying it is not use. Compaction and session replacement
clear load eligibility.

Manual ranking is still available when explicitly requested:

```bash
sage suggest skill "review this smart contract" --format json
```

That command does not inject a skill into Pi. Load the chosen full procedure
through Pi's native flow before using it.

## SDK Integration

```typescript
import {
  createAgentSession,
  createCodingTools,
  type ToolDefinition as PiToolDefinition,
} from '@earendil-works/pi-coding-agent';
import {
  createSageSessionConfig,
  type ToolDefinition as SageToolDefinition,
} from '@sage-protocol/pi-adapter';

function asPiCustomTools(tools: SageToolDefinition[]): PiToolDefinition[] {
  // Type-shape compatibility across supported Pi minors; no runtime conversion.
  return tools as unknown as PiToolDefinition[];
}

const sage = await createSageSessionConfig({
  sageBin: 'sage',
  source: 'pi-agent-core',
  enableRlmFeedback: true,
  enableSecurityHooks: true,
  // Choose exactly one complete mode. Glove normally injects inherited mode.
  gloveLocalServiceFdsV1: process.env.GLOVE_LOCAL_SERVICE_FDS_V1,
  gloveGuestChannelServiceAlias:
    process.env.GLOVE_GUEST_CHANNEL_SERVICE_ALIAS,
  // Legacy compatibility mode (omit all three when inherited mode is present).
  gloveGuestChannelEndpoint: process.env.GLOVE_GUEST_CHANNEL_ENDPOINT,
  gloveGuestChannelRoot: process.env.GLOVE_GUEST_CHANNEL_ROOT,
  gloveGuestChannelOwnerUid: process.env.GLOVE_GUEST_CHANNEL_OWNER_UID
    ? Number(process.env.GLOVE_GUEST_CHANNEL_OWNER_UID)
    : undefined,
});
const cwd = process.cwd();
const securedTools = sage.wrapToolsWithSecurity(createCodingTools(cwd));
const { session } = await createAgentSession({
  cwd,
  model,
  noTools: 'builtin',
  customTools: asPiCustomTools([...securedTools, ...sage.customTools]),
});

const disposeSageHooks = sage.setupHooks(session);
// on teardown: disposeSageHooks(); await sage.mcpBridge.stop();
```

Pi's `tools` option is a string allowlist, not a tool-definition array. The
helper isolates the only compatibility cast between the adapter's tool shape,
which spans supported Pi minors, and Pi's generic `ToolDefinition`; it performs
no runtime conversion.

The packaged Pi extension contains the Pi event-level native-load observer and
`sage_mark_guided_use` registration. A custom SDK host that bypasses the
extension must provide equivalent Pi event wiring if it wants those extension
features; `createSageSessionConfig` still supplies bridge, SessionStart,
capture, and security integration.

## Plugin Pattern

```typescript
export async function setupSagePlugin(runtime) {
  const sage = await createSageSessionConfig({ source: 'pi-agent-core' });
  const cwd = process.cwd();
  const securedTools = sage.wrapToolsWithSecurity(runtime.createCodingTools(cwd));

  // Pseudo host API: register definitions as custom tools before session creation.
  runtime.registerCustomTools([...securedTools, ...sage.customTools]);
  const { session } = await runtime.makeSession({
    cwd,
    model: runtime.model,
    noTools: 'builtin',
  });
  const dispose = sage.setupHooks(session);
  return {
    session,
    dispose: async () => { dispose(); await sage.mcpBridge.stop(); },
  };
}
```

A plugin host may name `registerCustomTools` differently; use its own custom-tool
registration API. Do not put definitions in a `tools` option.

## Environment Variables

| Variable | Default | Description |
|----------|---------|-------------|
| `SAGE_BIN` | `sage` | Path to Sage CLI |
| `SAGE_PROFILE` | — | Sage config profile (for example `testnet`) |
| `SAGE_SECURITY_HOOKS` | `1` | Enable pre/post-tool security scanning |
| `SAGE_RLM_FEEDBACK` | `1` | Enable prompt/response capture and native-use receipts |
| `SAGE_SHOW_HOOK_MESSAGES` | `0` | Display SessionStart hook messages in the chat UI |
| `SAGE_ALLOW_BASH_CLI` | `1` | Allow direct `sage ...` bash calls |
| `SAGE_AUTO_RESOLVE_SKILLS` | `1` | Resolve skills explicitly named in subagent tasks |
| `SAGE_INJECT_TOOL_DOCS` | `1` | Add compact Sage tool guardrails each turn |
| `GLOVE_LOCAL_SERVICE_FDS_V1` | — | Exact bounded JSON object mapping the one service alias to its inherited connected FD |
| `GLOVE_GUEST_CHANNEL_SERVICE_ALIAS` | — | Exact alias selecting the wallet-status service entry |
| `GLOVE_GUEST_CHANNEL_ENDPOINT` | — | Legacy canonical absolute guest-visible Unix socket path |
| `GLOVE_GUEST_CHANNEL_ROOT` | — | Legacy canonical absolute trusted root containing the endpoint |
| `GLOVE_GUEST_CHANNEL_OWNER_UID` | — | Legacy strict nonnegative decimal UID that owns the socket; must differ from the Pi process UID |

Choose exactly one complete mode. Inherited mode requires the FD map and alias while all three legacy variables are absent. Legacy mode requires the endpoint/root/owner tuple while both inherited variables are absent. Mixed and partial declarations fail closed and expose no wallet tool.

Inherited mode accepts exactly one own alias entry with an integer FD from 3 through 1,048,575. It uses that already-connected Unix stream persistently, permits one in-flight status request with no queue, and permanently disables the channel after any protocol, timeout, cancellation, disconnect, write, or reuse failure. It never falls back to a pathname.

Legacy mode preserves its existing pathname authentication: the adapter rejects relative or non-canonical paths, endpoints outside the root, symlinks, non-sockets, unsafe directory authority, owner mismatches, and socket inode changes across connect. There are no endpoint, root, owner, alias, or descriptor defaults.

### Deprecated Low-Level Compatibility

`suggestLimit`, `suggestDebounceMs`, and `enableProvision` remain exported in
`SageP2Config` for low-level legacy callers. The default Pi path ignores them;
do not use them in new configuration. `sageInjectSuggestion(...)` is likewise
a deprecated no-op in 0.4.

## Project Config

For monorepo development, keep Pi thin and point it at the curated Sage Pi
export surface:

```json
{
  "packages": [
    "../packages/sage-pi-adapter",
    {
      "source": "../packages/sage-pi-export",
      "skills": ["skills/*/SKILL.md"]
    }
  ],
  "enableSkillCommands": true
}
```
