This document is a step-by-step guide for converting the Chronos standalone agent into a
pi-package. After the migration, users install Chronos via pi install and run it through the
standard pi CLI. All existing tools, skills, and VS Code integration remain functional.
- Why Migrate?
- Core Design Changes
- What Changes, What Stays
- New Package Layout
- Step-by-Step Migration
- Step 1 – Create the new package skeleton
- Step 2 – Move tool and utility files
- Step 3 – Write the extension entry point
- Step 4 – The /select-source command
- Step 5 – Workspace init in session_start
- Step 6 – System prompt via before_agent_start
- Step 7 – Rewrite the system prompt template
- Step 8 – IPC streaming via pi events
- Step 9 – Bash confirmation hook
- Step 10 – Migrate skills
- Step 11 – Remove deleted files
- Step 12 – Update package.json
- VS Code Extension Changes
- What Is Lost and Why It's Fine
- User-Facing Workflow After Migration
Currently Chronos is a standalone binary that reimplements substantial infrastructure that pi
already provides: session management, TUI rendering, model selection, the interactive REPL,
/compact, /tree, conversation history, and more. As a pi-package:
- All of that infrastructure is inherited for free and stays up to date.
- Users get pi's full feature set (model switching, session branching,
/compact, keyboard shortcuts, etc.) without Chronos having to maintain any of it. - Chronos tools and skills become composable with any other pi package installed by the user.
- Installation is a single
pi installcommand instead of a separate npm global install. - The VS Code extension continues to work without changes to the IPC protocol.
The current design requires --source and --workspace flags at startup, and builds the system
prompt once at session creation. The new design is simpler:
Workspace = cwd. When the user runs pi from inside a Chronos workspace directory, the
extension detects the workspace from ctx.cwd. No --workspace flag is needed.
Source selection at runtime via /select-source. Instead of a --source flag, a
/select-source command walks the workspace's sources/ directory, presents a tree of available
sources with page counts, and lets the user pick one interactively. The selection updates the
shared SourceContext and informs the model. The existing change_source tool remains for cases
where the model switches sources on its own.
System prompt via before_agent_start. The Chronos system prompt (agent identity, workspace
conventions, tool descriptions, memory, current source state) is injected on every turn via the
before_agent_start event hook. The workspace root is always ctx.cwd. The template is
rewritten to explain the workspace folder structure, the VS Code integration features, and all
Chronos tools — so the agent understands the full environment it is operating in.
| Concern | Current | After migration |
|---|---|---|
| Entry point | chronos binary (agent/index.ts) |
Removed — user runs pi |
| Custom tools | extension.ts + tools/*.ts |
extensions/index.ts (same ExtensionAPI) |
--source flag |
parseArgs() in config.ts |
Removed — use /select-source command |
--workspace flag |
parseArgs() in config.ts |
Removed — workspace is ctx.cwd |
--task flag |
parseArgs() |
Removed — use /skill:name (pi standard) |
--model flag |
parseArgs() |
Removed — use pi's native --model / /model |
| Source selection | Startup flag | /select-source command (interactive, runtime) |
| Workspace root | Flag value or DEFAULT_WORKSPACE |
Always ctx.cwd |
| System prompt | Built once in create-session.ts |
Injected every turn via before_agent_start |
| System prompt content | Focused on dynamic state | Extended: explains folder structure, VS Code integration, all tools |
| Workspace init | ensureWorkspace() in index.ts |
session_start event handler |
| Session directory | <workspace>/sessions/ via custom SessionManager |
session_directory event → <cwd>/sessions/ |
| VS Code IPC | Connected unconditionally in index.ts |
Connected in session_start if CHRONOS_IPC_SOCKET is set |
| IPC streaming | session.subscribe() in index.ts |
message_update / tool_execution_start/end events |
| Skills | User-authored in <workspace>/skills/ |
Shipped built-in skills in skills/ + user workspace skills |
| Bash confirmation | tool_call hook in extension.ts |
Same |
noExtensions: true |
Blocks all other extensions | Dropped — composability is a feature |
agentsFilesOverride |
Blocks pi's AGENTS.md discovery | Dropped — conventions are in system-prompt.md |
chronos/
├── package.json
├── tsconfig.json
├── extensions/
│ └── index.ts ← NEW: pi extension entry point (replaces agent/index.ts + extension.ts)
├── tools/ ← moved from agent/tools/ verbatim
│ ├── ask-pages-batch.ts
│ ├── change-source.ts
│ ├── follow-up-question.ts
│ ├── list-pages.ts
│ ├── page-expert-state.ts
│ ├── show-page.ts
│ ├── show-text.ts
│ ├── source-context.ts
│ └── view-page.ts
├── utils/ ← moved from agent/utils/ verbatim
│ ├── crop-image.ts
│ ├── page-files.ts
│ ├── source-discovery.ts
│ ├── source-folder.ts
│ ├── tool-loader.ts
│ └── workspace.ts
├── ipc/ ← moved from agent/ipc/ verbatim
│ └── ipc-client.ts
├── prompts/ ← moved from agent/prompts/; system-prompt.md is rewritten
│ ├── ask-page.md
│ ├── ask-pages-batch.md
│ ├── change-source.md
│ ├── follow-up-question.md
│ ├── list-pages.md
│ ├── page-expert-prompt.md
│ ├── show-page.md
│ ├── show-text.md
│ └── system-prompt.md ← REWRITTEN (see Step 7)
└── skills/ ← NEW: built-in shipped skills
Files deleted:
agent/index.tsagent/config.tsagent/create-session.tsagent/system-prompt.tsagent/extension.tsagent/prompts/soul.md— content folded intosystem-prompt.mdagent/prompts/agents.md— content folded intosystem-prompt.md
cd chronos/
mkdir -p extensions skills
mv agent/tools tools
mv agent/utils utils
mv agent/ipc ipc
mv agent/prompts promptsAll files under tools/, utils/, and ipc/ are moved verbatim. The only thing that breaks is
import paths. Because tools/ is now at the package root rather than under agent/, fix the
relative imports:
- In
tools/*.ts:../ipc/ipc-client.js→../../ipc/ipc-client.js - In
tools/*.ts:../utils/→../../utils/
Run a project-wide find-and-replace on just the moved files. No logic changes are needed.
Create extensions/index.ts. This is the single file pi loads as a pi extension. It must export
a default function that receives ExtensionAPI. All the logic from agent/index.ts and
agent/extension.ts moves here.
The top-level structure:
// extensions/index.ts
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
import { isToolCallEventType } from "@mariozechner/pi-coding-agent";
import { existsSync, mkdirSync, readdirSync, statSync } from "node:fs";
import { join, basename, resolve, dirname } from "node:path";
import { fileURLToPath } from "node:url";
import { createSourceContext, type SourceContext } from "../tools/source-context.js";
import { createListPagesTool } from "../tools/list-pages.js";
import { createAnalyzePageTool } from "../tools/view-page.js";
import { createShowPageTool } from "../tools/show-page.js";
import { createShowTextTool } from "../tools/show-text.js";
import { createFollowUpQuestionTool } from "../tools/follow-up-question.js";
import { createChangeSourceTool } from "../tools/change-source.js";
import { createAskPagesBatchTool } from "../tools/ask-pages-batch.js";
import { createPageExpertState } from "../tools/page-expert-state.js";
import { loadToolText, loadPromptFile } from "../utils/tool-loader.js";
import { listPageIds } from "../utils/page-files.js";
import { ensureWorkspace } from "../utils/workspace.js";
import { connectIpc, sendToExtension, disconnectIpc } from "../ipc/ipc-client.js";
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const PROMPTS_DIR = join(__dirname, "..", "prompts");
export default function (pi: ExtensionAPI) {
// Shared mutable source context — updated by /select-source and change_source tool
const sourceCtx: SourceContext = createSourceContext(null, null, null);
// Register all custom tools
const pageExpertState = createPageExpertState();
const pageExpertPrompt = loadPromptFile("page-expert-prompt.md");
// Tools are registered once here; they close over sourceCtx and read
// ctx.cwd at execute-time for the workspace root.
// See Steps 4–9 for events and commands.
// ... (see subsequent steps for event hooks and the /select-source command)
}The sourceCtx object is the single piece of mutable state shared between all tools and the
/select-source command. Mutating it is safe because tools read it at execute() time.
Register tools inside the default function exactly as in the current extension.ts, pointing
createChangeSourceTool at ctx.cwd (read at execute time, not at load time — see note in
Step 4).
Register a /select-source command that walks the workspace's sources/ directory, lets the
user pick a source interactively, updates sourceCtx, and informs the model.
// Inside the default export function, after registering tools:
function discoverSources(workspaceDir: string): Array<{ label: string; path: string }> {
const sourcesDir = join(workspaceDir, "sources");
const results: Array<{ label: string; path: string }> = [];
function walk(dir: string): void {
let entries: string[];
try { entries = readdirSync(dir); } catch { return; }
if (existsSync(join(dir, "png")) && statSync(join(dir, "png")).isDirectory()) {
const pages = listPageIds(dir).length;
const rel = dir.slice(sourcesDir.length + 1); // relative to sources/
results.push({ label: `${rel} (${pages} pages)`, path: dir });
return;
}
for (const entry of entries) {
const full = join(dir, entry);
try {
if (statSync(full).isDirectory() && !entry.startsWith(".")) walk(full);
} catch { /* skip unreadable */ }
}
}
walk(sourcesDir);
return results.sort((a, b) => a.label.localeCompare(b.label));
}
pi.registerCommand("select-source", {
description: "Browse the workspace sources/ tree and select a source to work with",
handler: async (_args, ctx) => {
const workspaceDir = ctx.cwd;
const sources = discoverSources(workspaceDir);
if (sources.length === 0) {
ctx.ui.notify(
"No sources found. Add a directory with a png/ subfolder under sources/.",
"warning"
);
return;
}
const items = sources.map(s => s.label);
const selected = await ctx.ui.select("Select a source", items);
if (!selected) return;
const source = sources.find(s => s.label === selected)!;
const sourceName = basename(source.path);
const sourceDataDir = join(workspaceDir, "data", sourceName);
mkdirSync(sourceDataDir, { recursive: true });
// Update shared context — all tools pick this up on their next call
sourceCtx.sourceDir = source.path;
sourceCtx.sourceName = sourceName;
sourceCtx.sourceDataDir = sourceDataDir;
// Show the first page in the VS Code viewer if IPC is active
sendToExtension({
type: "show_page",
pageId: 1,
totalPages: listPageIds(source.path).length,
sourceDir: source.path,
sourceName,
bbox: null,
});
// Inform the model so it acknowledges the new source
pi.sendUserMessage(
`Source selected: "${sourceName}" at ${source.path}. ` +
`Please acknowledge and confirm you are ready to work with this source.`,
{ deliverAs: "followUp" }
);
ctx.ui.notify(`Source: ${sourceName}`, "success");
},
});Why pi.sendUserMessage instead of a tool call: Commands run outside the agent loop.
sendUserMessage with deliverAs: "followUp" queues the message to be delivered once the agent
is idle, triggering a new turn where the model acknowledges the switch. The model then knows to
use the source-specific tools without being told again.
change_source tool stays: The tool is still needed for when the model switches sources
programmatically (e.g., when processing multiple sources in a task). It reads ctx.cwd at
execute time to find the workspace root:
// In createChangeSourceTool, replace the hardcoded dataDir parameter with a
// dataDir getter that reads ctx.cwd at execute time.
// Pass a function () => join(ctx.cwd, "data") instead of the pre-resolved dataDir string.
// This avoids the need for the --workspace flag.Move ensureWorkspace() into session_start. The workspace root is ctx.cwd.
Also connect the IPC client here (conditionally — connectIpc() already checks for the
CHRONOS_IPC_SOCKET environment variable).
pi.on("session_start", async (_event, ctx) => {
ensureWorkspace(ctx.cwd);
connectIpc();
});
pi.on("session_shutdown", async (_event, _ctx) => {
disconnectIpc();
});Redirect session storage so Chronos sessions stay inside the workspace rather than pi's global session directory:
pi.on("session_directory", async (event) => {
// event.cwd is available at this early startup hook
return { sessionDir: join(event.cwd, "sessions") };
});Inject the full Chronos system prompt on every turn. The workspace root is ctx.cwd. Source
state comes from sourceCtx (the shared closure variable). Memory files are re-read on each
turn, so changes the agent made in the previous turn are visible immediately.
import { readFileSync, existsSync } from "node:fs";
function buildChronosSystemPrompt(sourceCtx: SourceContext, cwd: string): string {
const memoryDir = join(cwd, "memory");
const skillsDir = join(cwd, "skills");
const dataDir = join(cwd, "data");
const template = readFileSync(join(PROMPTS_DIR, "system-prompt.md"), "utf-8");
const resolvedSourceDir = sourceCtx.sourceDir ?? "(no source selected — use /select-source)";
const resolvedSourceName = sourceCtx.sourceName ?? "(no source selected)";
const sourceDataDir = sourceCtx.sourceDataDir ?? "(no source selected)";
const sourceMemoryPath = sourceCtx.sourceName
? join(memoryDir, `${sourceCtx.sourceName}.md`)
: "(no source selected)";
let documentMemory = "";
if (sourceCtx.sourceName) {
const mp = join(memoryDir, `${sourceCtx.sourceName}.md`);
if (existsSync(mp)) documentMemory = readFileSync(mp, "utf-8").trim();
}
let globalMemory = "";
const gmp = join(memoryDir, "MEMORY.MD");
if (existsSync(gmp)) globalMemory = readFileSync(gmp, "utf-8").trim();
return template
.replaceAll("{{workspaceDir}}", cwd)
.replaceAll("{{sourceDir}}", resolvedSourceDir)
.replaceAll("{{sourceName}}", resolvedSourceName)
.replaceAll("{{memoryDir}}", memoryDir)
.replaceAll("{{sourceMemoryPath}}", sourceMemoryPath)
.replaceAll("{{sourceDataDir}}", sourceDataDir)
.replaceAll("{{skillsDir}}", skillsDir)
.replaceAll("{{dataDir}}", dataDir)
.replaceAll("{{documentMemory}}", documentMemory)
.replaceAll("{{globalMemory}}", globalMemory);
}
pi.on("before_agent_start", async (_event, ctx) => {
return { systemPrompt: buildChronosSystemPrompt(sourceCtx, ctx.cwd) };
});The current system-prompt.md assumes the agent understands the workspace structure implicitly.
Rewrite it to explicitly explain:
- What a Chronos workspace is and how its folders relate to each other
- VS Code extension features the agent can use (page viewer,
[view p.N]links) - Every available Chronos tool with usage guidance
- The memory system
- The current source state
Below is the full structure of the new system-prompt.md:
## What you are
You are a document analysis agent. You help users analyze scanned pages, extract structured
data, and build up knowledge about archival sources (historical city directories, registries, etc.).
You are NOT a general coding agent. You use file tools only to read and write outputs and
memory — not to write application code.
## Workspace layout
Your working directory IS the workspace root: `{{workspaceDir}}`
| Directory | Purpose |
|-----------|---------|
| `sources/` | Input: scanned source directories. Each contains a `png/` subfolder with page images named `page_NNNN.png`. |
| `data/` | Output: per-source extraction results, summaries, JSON. Write all outputs here. |
| `memory/` | Your persistent memory. `MEMORY.MD` for cross-source insights. `<source-name>.md` for per-source findings. |
| `skills/` | Task instructions. Each skill is a `SKILL.md` file in a named subdirectory. |
| `sessions/` | Conversation history (auto-managed, do not edit). |
| `.chronos/` | API key only (`.env`). |
**Source data** for the current source goes in `{{sourceDataDir}}/`.
Never write output files directly into the source directory (`{{sourceDir}}/`).
## VS Code integration
If you are running inside VS Code via the Chronos extension, a page viewer panel is open
alongside your terminal. You can interact with it:
- **`show_page`** — displays a specific page in the viewer (no analysis, instant).
- **`list_pages`** — lists available pages AND updates the viewer's page-range indicator.
- **`ask_page`** — after analysis, the tool emits a `[view p.N]` link in the terminal.
The user can click it to jump to that page in the viewer.
- **`[view p.N]` links** — any time you write `[view p.N]` in your response (e.g.
`[view p.42]`), it becomes a clickable link in the terminal that opens page 42.
Use these affordances freely. The viewer updates in real time as you call tools.
## Available tools
### Source navigation
- **`/select-source`** *(user command)* — interactive source picker. The user types this to
choose which source to work on. It updates your source context automatically.
- **`change_source(source_path)`** — switch to a different source programmatically. Use this
when a task requires processing multiple sources.
- **`list_pages`** — list all page IDs in the current source. Always call this first when
starting work on a new source to understand the page range.
### Page analysis
- **`ask_page(page_id, prompt, [model], [output_file], [bbox])`** — send a page image to a
specialist vision model with a prompt. Returns a text analysis. Starts a new conversation —
use `follow_up_question` to continue without re-sending the image.
- **`follow_up_question(prompt)`** — continue the last `ask_page` conversation. Use for
clarifications like "What did that abbreviation mean?" or "Which entries were ambiguous?".
- **`ask_pages_batch(page_ids, prompt, [model], [output_file], [concurrency], [bbox])`** —
process many pages in parallel. **Requires explicit user confirmation before calling.**
See the mandatory protocol below.
- **`show_page(page_id, [bbox])`** — display a page in the VS Code viewer without analyzing it.
### File tools
- **`read`**, **`edit`**, **`write`**, **`grep`**, **`find`**, **`ls`** — standard file tools.
- Use `read` for text files only. Never `read` a PNG — use `ask_page` instead.
- Use `grep`/`find`/`ls` for file exploration (faster than `read` for discovery).
- Use `edit` for precise surgical changes (oldText must match exactly).
- Use `write` only for new files or complete rewrites.
## Mandatory Confirmation Protocol — `ask_pages_batch`
`ask_pages_batch` is high-cost and irreversible. Follow this protocol every time, without
exception:
1. **Propose** — In a single message with no tool calls: state the intent, exact page range,
the full prompt in a code block, the model and rationale, and the output plan.
2. **Ask** — End the message with an explicit go/no-go question.
3. **Stop** — End your turn. Do not call any tools. Wait for the user's reply.
4. **Execute** — Only after receiving explicit confirmation (e.g. "yes", "go ahead").
## Memory system
Memory is how you persist knowledge across sessions. Write early and often.
### Global memory: `{{memoryDir}}/MEMORY.MD`
Cross-source insights: recurring conventions, abbreviation patterns, lessons learned,
tool tips. Update this after any session where you learned something reusable.
### Per-source memory: `{{sourceMemoryPath}}`
Everything about the current source: table of contents, page ranges for sections,
layout observations, content insights, anomalies, progress notes.
Write after every ~5–10 pages analyzed. Do not wait until the end of a task.
Always `read` before writing, then use `edit` to append.
### Current global memory
{{globalMemory}}
### Current source memory
{{documentMemory}}
## Current source
Source name: **{{sourceName}}**
Source path: `{{sourceDir}}`
Source data: `{{sourceDataDir}}/`
Source memory: `{{sourceMemoryPath}}`
Skills directory: `{{skillsDir}}/`The key changes from the old template:
- Soul and workspace conventions are inlined — no
{{soul}}or{{agents}}variables, no.chronos/SOUL.MDor.chronos/AGENTS.mdfiles - Workspace layout table — the agent understands every folder's purpose
- VS Code integration section — explains the page viewer, clickable links, how tools interact with it
- Expanded tool reference — every tool with parameters and usage notes in one place
- Global memory injected alongside source memory
Replace the session.subscribe() block in index.ts with pi event handlers. The IPC client
module is unchanged — it already gates all sends on the socket being connected.
pi.on("message_update", async (event, _ctx) => {
const e = event.assistantMessageEvent;
if (e.type === "text_delta") {
sendToExtension({ type: "text_delta", delta: e.delta });
}
});
pi.on("tool_execution_start", async (event, _ctx) => {
const argsStr = JSON.stringify(event.args).slice(0, 200);
sendToExtension({ type: "tool_start", toolName: event.toolName, args: argsStr });
});
pi.on("tool_execution_end", async (event, _ctx) => {
const result = event.result;
const resultText =
typeof result === "object" && result?.content
? (result.content as any[])
.filter((c) => c.type === "text")
.map((c) => c.text)
.join("")
: String(result);
sendToExtension({ type: "tool_end", toolName: event.toolName, result: resultText.slice(0, 500) });
});
pi.on("agent_end", async (_event, _ctx) => {
sendToExtension({ type: "turn_end" });
});This is unchanged from the current extension.ts. Keep it as-is:
pi.on("tool_call", async (event, _ctx) => {
if (!isToolCallEventType("bash", event)) return;
const approved = await confirmBashCommand(event.input.command);
if (!approved) return { block: true, reason: "User denied bash command" };
});
function confirmBashCommand(command: string): Promise<boolean> {
// readline confirmation as in current extension.ts
}Built-in skills that should ship with the package go in skills/. Pi auto-discovers them
from this conventional directory. The SKILL.md format is already fully compatible with the
pi Agent Skills standard — no changes needed.
User-authored skills should go in .pi/skills/ or .agents/skills/ inside the workspace,
or the user can add their workspace skills/ directory to their pi settings:
{ "skills": ["./skills"] }Skills with index.ts custom tools: The old system dynamically imported a skill's
index.ts at task activation time. Pi does not support this. The recommended approach is to
move any skill-specific tools into the main extension in extensions/index.ts. Since all
Chronos skills share SourceContext, the tools belong in the extension anyway. If a skill's
tools are truly standalone, they can be a separate pi extension in a sub-package.
rm agent/index.ts
rm agent/config.ts
rm agent/create-session.ts
rm agent/system-prompt.ts
rm agent/extension.ts
rm agent/prompts/soul.md # content folded into system-prompt.md
rm agent/prompts/agents.md # content folded into system-prompt.md
rmdir agent/ # if empty{
"name": "@you/chronos",
"version": "1.1.0",
"description": "AI agent for digitizing historical German city directories",
"type": "module",
"keywords": ["pi-package"],
"pi": {
"extensions": ["./extensions"],
"skills": ["./skills"],
"prompts": ["./prompts"]
},
"peerDependencies": {
"@mariozechner/pi-ai": "*",
"@mariozechner/pi-coding-agent": "*",
"@sinclair/typebox": "*"
},
"dependencies": {
"dotenv": "^16.4.0",
"sharp": "^0.34.5"
},
"devDependencies": {
"@types/node": "^22.0.0",
"tsx": "^4.19.0",
"typescript": "^5.7.0"
},
"scripts": {
"build": "tsc"
}
}Key changes from the current package.json:
- Remove
"bin"— nochronoscommand. - Remove
"files": ["dist/"]and the build-time prompt copy — prompts are loaded from source by pi's jiti loader, no compilation step needed during development. - Add
"keywords": ["pi-package"]for gallery discoverability. - Add
"pi"manifest pointing atextensions/,skills/,prompts/. - Move
@mariozechner/pi-aiand@mariozechner/pi-coding-agenttopeerDependencies— pi bundles these; listing them as regulardependencieswould cause duplicate modules. - Keep
sharpanddotenvindependencies— these are not bundled by pi.
The VS Code extension (chronos-vscode/) requires no changes to the IPC protocol
(protocol.ts is unchanged) and no changes to the page viewer.
The only change is in extension.ts: the startSession command no longer needs to pass
--source or --workspace flags. The workspace is the open VS Code folder (already cwd).
Source selection happens via /select-source at runtime.
Before:
shellArgs: [
"npx", "chronos",
"--source", sourceDir,
"--workspace", workspaceFolder,
]After:
shellArgs: ["pi"] // or: ["npx", "@mariozechner/pi-coding-agent"]The terminal is already opened with cwd: workspaceFolder so pi starts in the right directory.
The CHRONOS_IPC_SOCKET env var is still set so IPC connects automatically.
The source picker UI in the extension (showQuickPick in the current startSession command) is
no longer needed — source selection moved into the pi TUI via /select-source. The
Chronos: Start Agent Session command becomes simpler: just open a terminal running pi.
The page viewer still opens on page 1 when the IPC receives a show_page message from the
/select-source command (see Step 4), so the VS Code workflow is seamless.
noExtensions: true
Dropping this means the user's global/project pi extensions also load. That is the desired
behavior — composability. If a user's extension conflicts with a Chronos tool name, they can
filter packages via pi settings.
agentsFilesOverride
Dropped. Workspace conventions are now part of system-prompt.md itself, injected via
before_agent_start. There is no separate AGENTS.md to discover or suppress.
--task flag
Replaced by /skill:name. This is strictly better: it shows in autocomplete, describes the
skill, and is consistent with any other pi skill package.
--model flag
Pi supports --model natively. The flag is not lost — it just comes from pi instead of custom
parseArgs() code.
The chronos binary
Users run pi instead. For users who want the old chronos alias:
#!/bin/sh
exec pi "$@"Install:
pi install npm:@you/chronos
# or from a local checkout:
pi install ./path/to/chronosRun from a workspace directory:
cd ~/my-chronos-workspace
piPi starts, the extension initializes the workspace if needed, and the agent is ready.
Select a source:
/select-source
A picker appears with all sources found under sources/. After selection the agent
acknowledges the source and is ready to work.
Run a skill:
/skill:extract-entries
VS Code:
Open the workspace folder in VS Code, run Chronos: Start Agent Session. The extension opens
a terminal running pi in the workspace directory with CHRONOS_IPC_SOCKET set. Type
/select-source to pick a source — the page viewer opens automatically.