npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

sagent-ai

v2.2.34

Published

SAgent AI auto installer and launcher for Windows and Linux

Readme

SAgent AI

SAgent AI is a compact DSL coding agent based on OpenAI Codex.

The core idea is simple: keep the Codex foundation, but replace the model-visible tool surface with one compact raw DSL tool: dsl.

Release 2.2.32 hardens the refreshed Codex integration with Unicode-safe Windows background scripts, protocol-matched sandbox resources, semantic-index recovery, and more complete release checks while preserving direct dsl access.

Instead of many JSON tool calls, the model writes a readable script of actions:

RG --summary "GameEngine" src
READ --outline src/game/engine.ts
READ --def createSnapshot src/game/engine.ts
USES createSnapshot src --summary
REPLACE src/game/engine.ts --def `export function createSnapshot() {
  return { ok: true }
}
`
RUN `npm test
`

No JSON escaping. No JSON-escaped multi-line patches. The conversation history stays readable.


Install

npm install -g sagent-ai
sagent

sagent-ai is a small auto installer/launcher package.

It installs and runs the native package for the current platform:

Windows x64 -> sagent-ai-win
Linux x64   -> sagent-ai-linux

Direct platform packages:

npm install -g sagent-ai-win
npm install -g sagent-ai-linux

Requirements:

  • Windows x64 or Linux x64;
  • Node.js 22.6+ and npm for installation and EXEC / JS scripting;
  • CodeGraph support for CG is installed as the optional npm dependency @colbymchenry/codegraph under the sagent-ai package; SAgent falls back to a global codegraph binary if needed.
  • SEM semantic search uses Ollama with qwen3-embedding:4b by default and can be configured to use OpenAI embeddings instead.

Use

Start in the current project:

sagent

Start in a specific project:

sagent -C C:\path\to\project

Run a non-interactive task:

sagent exec "inspect the project, fix the failing test, and run the checks"

Run JavaScript automation inside a DSL batch with EXEC:

EXEC --timeout 30 `const outline = await dsl.READ("--outline src/app.ts");
const next = await dsl.ask(outline + "\nWhich definition should I inspect next?");
dsl.PRINT(next);
`

Inside EXEC, every regular DSL command is available as an async dsl.* helper with the same arguments and bodies as the line-command form. Only nested dsl.EXEC / dsl.JS are blocked.

EXEC also has direct Node.js access to the current project, network, and child processes. Node and every child inherit the same OS sandbox. Import packages installed in the project normally:

const ts = await import("typescript");
const { writeFile } = await import("node:fs/promises");
await writeFile(".agent-dsl/tmp/typescript-version.txt", ts.version);

Node resolves packages from the project node_modules; npm cache, prefix, home, and temp directories stay under .agent-dsl. EXEC clears the inherited host environment and exposes a small synthetic environment. Add a comma-separated [node.exec] env = "HTTP_PROXY,..." allowlist when specific host variables are required. If the platform sandbox runner is missing, EXEC fails closed instead of launching unsandboxed.

Reusable EXEC functions can live in .agent-dsl/exec/function/<name>.ts as plain async body code. SAgent wraps and caches them under .agent-dsl/exec/function/.compiled.

EXEC pick-ranges --limit 3 `raw search output...
`

Inside the function body, use dsl, dan, args, and argText directly:

const answer = await dsl.ask(`Choose ranges from:\n${dan}`);
await dsl.PRINT(answer);

The same function can be called from regular EXEC code:

const ranges = await dsl.function(`pick-ranges --limit 3
${searchOutput}`);

Use dsl.try.function(...) when a missing or failing helper should return { ok: false, error } instead of throwing.

Configurable ASK / GEN profiles

DSL summarization and generation helpers can use named profiles from:

  1. CLI overrides such as -c agent_dsl.llm.ask_profile="sonnet";
  2. project .agent-dsl/config.toml;
  3. global ~/.codex/.agent-dsl/config.toml;
  4. built-in defaults.

Example:

[llm]
ask_profile = "default"
gen_profile = "default"
fallback_profile = "gpt55-low"

[llm.profiles.sonnet]
model_provider = "claude"
model = "sonnet"
max_input_tokens = 100000
max_output_tokens = 4000

[node.exec]
env = "HTTP_PROXY,HTTPS_PROXY,NO_PROXY,NODE_EXTRA_CA_CERTS"

Built-in profiles are:

  • default — openai/gpt-5.3-codex-spark, reasoning low;
  • gpt55-low — openai/gpt-5.5, reasoning low;
  • gpt55-xhigh — openai/gpt-5.5, reasoning xhigh.

model_provider = "claude" uses the local claude CLI with tools disabled. Use profiles with --ask-profile, --gen-profile, ASK --profile name, or await dsl.ask(prompt, ["YES", "NO"], "gpt55-xhigh"). Unknown profiles fall back to default; unavailable profiles retry fallback_profile when configured, then default.

For noisy searches or summaries, add {{ranges}} to an --ask / --ask-full / ASK capture prompt when you want the ASK model to choose exact source ranges. SAgent removes the marker before asking, then expands returned links into real numbered snippets:

RG "handleSubmit" src --ask "{{ranges}} Pick the 1-3 ranges I should read next."

Single-file commands may return >>START-END; ASK capture and multi-file answers should return >>path:START-END. Duplicate or overlapping ranges are merged and capped.

Skills can be loaded on demand without adding the full Codex skills list to the system prompt:

SKILL --list
SKILL --list --paths
SKILL --find ast
SKILL ast-grep-cli
SKILL ast-grep-cli --ask "Give only commands useful for this task."

For one-off expert ASK prompts, inject a skill only into that ASK request:

RG "defineComponent" src --ask-profile gpt55-xhigh --ask "{{SKILL:ast-grep-cli}} Pick the safest ast-grep command."

{{SKILL:name}} works in global --ask / --ask-full, ASK --begin / ASK --end, normal ASK, and EXEC dsl.ask(...). Plain SKILL --list and SKILL --find show names, scopes, and descriptions without noisy paths; add --paths when you need exact locations. If a {{SKILL:name}} marker cannot be resolved, SAgent removes it from the ASK prompt and prefixes the visible answer with ASK_WITHOUT_SKILL ....

Reusable helper libraries can live in .agent-dsl/exec/lib and be imported from both regular EXEC scripts and named EXEC functions:

const { readRanges } = await dsl.lib("kit.ts");

dsl.lib("kit") defaults to kit.ts; paths are restricted to .agent-dsl/exec/lib. Bundled skill packages can also provide EXEC libraries and functions:

const kit = await dsl.lib("skill:exec-kit/kit.ts");
await dsl.function("skill:some-skill/function/check\ninput");

skill:name/path.ts resolves through the normal skill resolver and materializes the selected file under .agent-dsl/exec/.skill-cache before Node imports it. SKILL name remains read-only and never installs or runs code by itself.

SAgent loads:

  1. system.md from the same directory as sagent.exe;
  2. global and project AGENTS.md instructions.

The packaged SAgent build disables MCP startup to avoid unrelated MCP startup failures and reduce noise.


Version

Current npm package version: 2.2.32.

Highlights in this release:

  • Unicode and emoji-safe Windows background SH 0 / RUN 0 scripts;
  • resilient Windows background startup when a running PowerShell process temporarily locks its log file;
  • Windows sandbox helper binaries rebuilt and packaged with the same protocol version as SAgent;
  • automatic rebuilding after a corrupt semantic manifest;
  • release checks for semantic sidecars and sandbox resources;
  • WSL-backed Linux package version and artifact-freshness checks on Windows release hosts;
  • hosted image-result compatibility with both added and completed response items;
  • a hard whole-command deadline for standalone, captured, global, and generated ASK requests, preventing retry/fallback multiplication from looking like a hung dsl;
  • --timeout N now limits the complete ASK operation rather than every individual provider attempt;
  • cancellable async Claude CLI execution with child cleanup when an ASK times out;
  • synchronization with 157 upstream Codex commits, including GPT-5.6 metadata, persisted turn items, HTTP/proxy improvements, Windows sandbox fixes, and dependency security updates;
  • direct dsl exposure for new models even when their metadata requests code_mode_only;
  • restored compact TUI command, ASK, and ERR icons through the canonical command lifecycle;
  • native hybrid semantic search sidecars for Windows and Linux.

See CHANGELOG.md for release history and PLANNED_CHANGES.md for planned improvements.


Why SAgent is different

Raw DSL instead of JSON

dsl is a raw DSL, not JSON. The model writes commands directly:

READ src/app.ts
PATCH `*** Begin Patch
*** Update File: src/app.ts
@@
-console.log("old")
+console.log("new")
*** End Patch
`

This is easier for coding tasks because patches, regexes, shell scripts, and multi-line code do not need JSON string escaping.

Fewer tool calls

One batch can combine related work:

FILES src --limit 80
RG --summary "TODO|FIXME" src
READ --outline src/main.ts
RUN 120 `npm test
`

SAgent is designed to encourage this workflow:

  • search;
  • read;
  • edit;
  • run tests;
  • inspect logs;
  • continue from failure.

Prefer one comprehensive dsl per step instead of many tiny calls. The --ask and --gen modes use a fast, cheap single-shot model and are intended to reduce raw context and boilerplate while keeping work batched.

Recovery with RESUME

If a batch fails in the middle, completed commands are saved as done and the failed command plus the remaining commands stay in .agent-dsl/tasks/<N>.dsl.

The model can resume that saved task from anywhere in a later batch. Commands before and after RESUME still belong to the current batch:

NOTE before
RESUME 12 `old broken command text` `fixed command text`
NOTE after

Or skip a no-longer-needed failed command:

RESUME 12 --skip
RESUME 12 --skip 2

Successful work is not repeated.

If a resumed task fails, the current batch stops at RESUME. Use RESUME? ... when the resumed failure should be reported as a warning and the current batch should continue.

Passive feedback

SAgent appends useful passive blocks to later dsl results:

CURRENT_PLAN
2/5: Implement parser

UNREAD_LOGS
7 out=12 err=1
8 out=4

NOTIFICATIONS
- BG 7 exited:0 npm run dev

This helps the model track plans, background logs, and finished processes without extra status calls.

ASK summarization

SAgent can call a small single-shot model from the DSL.

ASK `Answer only OK if this README explains installation clearly.
`

Most commands also support a global --ask "prompt" post-processing argument:

RG "GameEngine" src --ask "Choose the 3 most relevant files to read next"
RUN 120 --ask "If tests failed, return only the failing file, error, and likely cause. If OK, answer OK." `npm test
`

The command runs normally, but the visible result is replaced by the ASK model's concise answer. This is useful for reducing large search, test, log, and web outputs. If the command fails, ASK receives the failure text and the command still fails unless the directive is optional with ?.

For edit commands, --ask sends the compact edit summary plus diff hunks to the ASK model. Use --ask-full "prompt" when the ASK model also needs post-edit file contents. Full-file context is hidden from the main model and is not added to the read journal. All fast-model requests (--ask, --ask-full, ASK, dsl.ask, and --gen) are capped to roughly a 100K-token prompt budget.

To keep history compact, visible command headers omit long --ask / --ask-full prompts and --gen, replacing them with short ASK, ASK_FULL, and GEN markers.

For multi-command summarization, use an ASK capture block:

ASK --begin
RG "GameEngine" src
READ --outline src/game/engine.ts
ASK --end `Summarize the captured output and choose the next 3 files to inspect.
`

Commands between ASK --begin and ASK --end run normally, but their visible output is captured and replaced by the single ASK answer. If a captured command fails before ASK --end, SAgent aborts the capture, prints the captured output, and the batch fails normally.

Every ASK has one wall-clock timeout budget shared by all retries and fallback profiles. --timeout N sets that whole-command budget for a standalone ASK; without an override, SAgent uses the largest timeout among the resolved profiles. A slow provider can no longer multiply its timeout by every retry and fallback.

Cheap context compression patterns

Use --ask on one noisy command when you only need a decision, ranking, or summary:

RG "handleSubmit" src --ask "Pick the 3 files most likely to need edits."
RUN 120 --ask "If failed: file, error, likely cause. If OK: answer OK." `npm test
`

Use ASK --begin / ASK --end to compress several command outputs into one answer:

ASK --begin
READ --outline src/a.ts
READ --outline src/b.ts
READ --outline src/c.ts
ASK --end `Choose the 1-2 files to inspect next and explain briefly.
`

Use two-level compression for broad searches: each command summarizes itself with --ask, then the final capture prompt chooses the next action:

ASK --begin
READ --outline src/a.ts --ask "Does this file contain auth logic? Briefly."
READ --outline src/b.ts --ask "Does this file contain auth logic? Briefly."
READ --outline src/c.ts --ask "Does this file contain auth logic? Briefly."
ASK --end `Choose the 1-2 files most likely relevant to the auth bug.
`

Command reference

Every command starts on a new line.

Append ? directly to a command name to make failure a warning and continue the batch.

Use backticks for short payloads and double a literal backtick inside them; backslashes remain literal. For multiline or backtick-heavy payloads, use an exact heredoc terminator:

CREATE tmp/change-note.txt <<TEXT
Тест переведён с фиксированной задержки на ожидание состояния ready.
TEXT

REPLACE file.txt <<OLD <<NEW
старая строка1
старая строка2
OLD
новая строка1
новая строка2
NEW

Declare heredoc markers in body order. Terminators must appear alone on a line, and body whitespace is preserved literally.


Read and inspect

READ path
READ --fresh path
READ -n path:10-40
READ --outline path
READ --def name[,name2] path
READ --fn name[,name2] path
USES name [path] [--all] [--summary]
FILES [path ...] [--limit N]
FILES [path ...] --hash
FILES [path ...] --changed
JSON path [dot.path]
RG [--summary] [--limit N] args...
CG query
CG [status|sync|query|explore|node|files|callers|callees|impact|affected] args...
SEM "natural language query"
SEM status
SEM [--path path] [--glob mask] [--ext ext] [--label name] [--no-tests] "query"
AROUND path "text" [--before N] [--after N]
EXPECT path exists
EXPECT path not-exists
EXPECT path contains "text"
EXPECT path not-contains "text"
EXPECT path --def name[,name2]
ASK [seconds|--timeout N] [--model model] `prompt text
`
ASK --begin
READ src/a.ts
READ src/b.ts
ASK --end `prompt for captured output
`
EXEC [seconds|--timeout N] `await dsl.READ("src/app.ts");
dsl.PRINT("visible output");

`
JS [seconds|--timeout N] `await dsl.RG('"GameEngine" src --summary');
`

Aliases:

READ --fn: --func
AROUND: READAROUND, LINES
READ --fresh: --force

CodeGraph (CG) uses the indexed project graph for fast symbol/file navigation and impact checks. First non-status use initializes .codegraph if needed; after file edits, SAgent starts a background codegraph sync when an index exists. Examples:

CG start_node_exec
CG --ask "Pick files, risks, and NEXT DSL." `start_node_exec
resolve_profile_attempts
`
CG impact start_node_exec --depth 3
CG node codex-rs/core/src/compact.rs

Semantic search (SEM) builds a project-local index under .agent-dsl/semantic and combines dense embeddings with lexical identifier matching. Indexing runs in the background through the packaged sagent-semantic-index sidecar, while queries use the read-only sagent-semantic-query sidecar.

SEM status
SEM "where is command execution rendered in the TUI?"
SEM --path codex-rs/core --no-tests "canonical tool lifecycle"
SEM --ask "{{ranges}} Pick the 3 ranges to inspect next." "command badge rendering"

Results include symbols, signatures, CodeGraph caller/callee context when available, and ready-to-use READ ranges. Scope, labels, embedding providers, and optional reranking can be configured in .agent-dsl/config.toml.

Structural commands support:

  • JavaScript;
  • TypeScript;
  • JSX / React;
  • TSX / React;
  • Vue SFC script and script setup;
  • Rust.

Structural commands include:

  • READ --outline;
  • READ --def;
  • READ --fn;
  • USES;
  • REPLACE --def;
  • COPY --def;
  • MOVE --def;
  • DELETE --def.
  • EXPECT --def.

Raw READ output is remembered in memory while it remains safe to assume the model has seen it. If the same unchanged file/range is read again, SAgent can answer with a short already read unchanged message instead of re-sending the content. READ -n records numbered coverage separately: raw READ can reuse raw or numbered coverage, while numbered READ only reuses numbered coverage. Use READ --fresh (or --force) when you need the bytes printed again. Reads hidden behind --ask, ASK --begin, or EXEC are not remembered, and the memory is cleared after context compaction.

EXPECT

Use EXPECT to assert preconditions before edits or postconditions after commands:

EXPECT src/game/engine.ts exists
EXPECT src/game/engine.ts contains "createSnapshot"
EXPECT src/game/engine.ts not-contains "legacySnapshot"
EXPECT src/game/engine.ts --def createSnapshot

If an expectation fails, the batch stops and the failed EXPECT plus following commands remain in .agent-dsl/tasks/<N>.dsl for RESUME.

Use EXPECT? ... for a soft check that warns and continues. Failure messages include matching lines, closest lines, or available definitions where possible.

READ --outline

Returns a structural map of the file:

  • imports;
  • top-level definitions;
  • classes and methods;
  • functions;
  • constants;
  • React components;
  • Vue definitions;
  • Rust items.

READ --def

Reads exact definitions by symbol name:

READ --def createSnapshot,GameEngine src/game/engine.ts

Use this instead of reading a whole large file when only specific definitions are needed.

USES --summary

Shows compact per-file usage counts:

USES createSnapshot src --summary

Use --all to include hidden or less direct references.

FILES --changed

Compares against the last FILES --hash baseline.

If no baseline exists, SAgent returns NO_BASELINE and continues the batch.

Global --ask

Use --ask "prompt" on a command when the raw output is large and you only need a model-produced answer:

SH --log 7 --ask "Extract the local dev server URL only"

ASK treats command output as untrusted data and answers the prompt without tools.

--ask is fast and cheap; use it to select the important parts from large READ, RG, test, log, and web outputs before loading more context.


EXEC / JS

EXEC runs JavaScript through ordinary Node.js inside the platform OS sandbox and gives the script async access to the same DSL command handlers that normal commands use.

EXEC --timeout 45 `const files = await dsl.FILES("src --limit 80");
const choice = await dsl.ask(files + "\nPick the 2 files most likely related to auth.");
dsl.PRINT(choice);
`

Key rules:

  • all regular DSL commands are available as await dsl.READ(...), await dsl.RG(...), await dsl.PATCH(...), await dsl.PLAN(...), etc.;

  • arguments and flags are the same as the text after COMMAND;

  • multiline command bodies use template strings passed separately from arguments; REPLACE accepts both old and new bodies:

    await dsl.PATCH('--gen src/game/engine.ts --ask "Summarize the change"', `
    Add a guard for empty enemy waves.
    Keep public signatures unchanged.`);
    await dsl.REPLACE('src/version.txt', `old value`, `new value`);
  • dsl.EXEC and dsl.JS are intentionally unavailable inside EXEC to avoid recursive script runners;

  • visible successful output must be written with dsl.PRINT(value) or dsl.print(value);

  • console.log / stdout are hidden on success and shown only as diagnostics when the script fails;

  • dsl.ask(prompt, choices?) calls the fast ASK model; choices can constrain answers, for example ["yes", "no"];

  • dsl.try.COMMAND(...) returns { ok, output } or { ok: false, error, response } instead of throwing;

  • persistent JSON state is available through dsl.state.set(key, value), dsl.state.get(key), and dsl.state.exists(key).

Generated scripts are stored under .agent-dsl/exec/<task>-<step>.mjs. The local RPC port and token are passed through environment variables and are not written into the script.

EXEC requires Node.js 22.6+. Windows uses the packaged codex-sandbox-runner.exe; Linux uses codex-linux-sandbox through the SAgent self-dispatch; macOS uses /usr/bin/sandbox-exec. There is no unsandboxed fallback. On Windows, ACL grants from older sandbox runs can persist, so use a VM or container for fully hostile code.


Edit files

CREATE path `file body

`
CREATE path --diff `file body

`
CREATE path --after `append body

`
CREATE path --before `prepend body

`
CREATE --gen path `instruction for generating the file/content

`
REPLACE path `old text` `new text
`
REPLACE path --after `anchor text` `inserted text
`
REPLACE path --before `anchor text` `inserted text
`
REPLACE path --def `export function name() {
  return true
}

`
REPLACE path --diff `old text` `new text
`
REPLACE --gen path --def name[,name2] `instruction for generating replacement definition bodies

`
PATCH `*** Begin Patch
*** Update File: file.txt
@@
-old
+new
*** End Patch

`
PATCH --diff `*** Begin Patch
*** Update File: file.txt
@@
-old
+new
*** End Patch

`
PATCH --gen path [path2 ...] `instruction for generating an apply_patch patch for only those files

`
COPY src -> dst
COPY src --def name[,name2] -> dst
MV src -> dst
MOVE src --def name[,name2] -> dst
DELETE path
DELETE path --def name[,name2]

Aliases:

COPY: CP
MV: MOVE, RENAME
DELETE: RM, DEL

Symbol-aware editing

Prefer REPLACE --def when replacing a whole function, class, component, or Rust item:

REPLACE src/file.ts --def `export function foo() {
  return 1
}

export function bar() {
  return 2
}
`

REPLACE --def:

  • takes only new definition bodies;
  • finds matching definitions by name;
  • can replace multiple definitions in one command;
  • validates replacement syntax before modifying the file.

Definition copy/move/delete

COPY src/game/engine.ts --def createSnapshot -> src/game/snapshot.ts
MOVE src/game/engine.ts --def createSnapshot -> src/game/snapshot.ts
DELETE src/game/engine.ts --def createSnapshot

These commands operate on named definitions instead of raw text.

They do not currently auto-fix imports, exports, or call-sites. A planned --fix-imports mode is listed in PLANNED_CHANGES.md.

Fast generated edits with --gen

--gen uses the same fast, cheap single-shot model as ASK to generate small, well-scoped edits without making the main model hand-write boilerplate.

CREATE --gen src/game/damage.ts `Create a small damage helper module with applyDamage(unit, amount).
Clamp health at 0 and export the function.

`
PATCH --gen src/game/engine.ts src/game/damage.ts `Use applyDamage from damage.ts in the engine damage flow.

`
REPLACE --gen src/game/engine.ts --def applyDamage `Keep the same signature, but clamp health at 0 and preserve existing return shape.
`
  • CREATE --gen path generates file/content text and writes it through CREATE.
  • PATCH --gen path... reads the listed files, asks for an apply_patch patch, verifies that only those files are touched, and applies it.
  • REPLACE --gen path --def name[,name2] reads the current definitions, asks for replacement definition bodies, and validates them through REPLACE --def.

Use --gen for targeted local edits, boilerplate, and tests. For broad architecture work, still inspect the code first and batch READ/PATCH/RUN together.

Syntax diagnostics

After file edits, SAgent prints compact summaries such as:

REPLACE src/app.ts M +3 -1

PATCH
M src/a.ts +3 -1
M src/b.ts +10 -4

For single-target CREATE and REPLACE, the target path is already in the command header, so the compact summary omits the duplicate path. PATCH keeps per-file paths because it can touch many files. Use --diff on CREATE, REPLACE, or PATCH when you need visible DIFF hunks. Otherwise, prefer the compact summary to save context. SAgent also runs parser-based syntax diagnostics for supported languages and prints SYNTAX WARN when it detects parse errors.

Diagnostics are tree-sitter based and may miss grammar-accepted invalid constructs.


Shell, tests, and background jobs

SH [seconds] `command body

`
RUN [seconds] `command body

`
SH 0 [--tty] `long-running command body

`
WAIT N
SH --status [job_id]
SH --stop [job_id]
SH --log job_id [--limit N]
SH --log job_id --all [--limit N]
SH --send job_id [--noAwait] [--timeout N] `input for the background process
`

SH and RUN execute shell commands from the project root. WAIT N pauses the batch for N seconds without invoking a shell, which is useful before checking background job logs.

Timed command

RUN 120 `npm test
`

Background command

SH 0 `npm run dev
`

Returns:

job_id=7
pid=12345
mode=normal
status=running

SH 0 starts outside the sandbox through the exec approval flow.

Interactive TTY job

SH 0 --tty `node
`

Send input:

SH --send 7 --timeout 3 `1 + 2
`

SH --send waits for output by default and advances the log cursor.

Use --noAwait to send without waiting.

For interactive programs such as SSH, SFTP, and REPLs, SAgent sends terminal Enter as CRLF.

Logs

SH --log 7

Returns only unread stdout/stderr since the previous log read and advances per-stream cursors.

SH --log 7 --all

Returns the full log without advancing cursors.

SH --log 7 --limit 50

In normal unread mode, keeps only the newest 50 unread lines, advances the cursor to the current log end, and reports omitted_before_limit=M if older unread lines were skipped.

For --tty jobs, the PTY stream is shown as STDOUT; STDERR is omitted.

Status and stop

SH --status
SH --status 7
SH --stop 7
SH --stop

SH --status lists only active jobs.

SH --stop kills the process tree.


Notes

NOTE short note

Adds a note to the batch output.


Recovery

STATUS [task_name] [--limit N]

Shows unfinished saved commands.

RESUME task_name `old text in saved task` `new text for saved task`

RESUME:

  1. loads .agent-dsl/tasks/<task_name>.dsl;
  2. optionally applies exact text replacement or --skip [N];
  3. runs that saved task separately;
  4. returns to the current task and continues commands after RESUME;
  5. moves successful resumed commands to <task_name>.ok;
  6. leaves failed and remaining resumed commands in <task_name>.dsl.

RESUME can appear anywhere in a batch and can be used multiple times. If it fails, the current task stops at the RESUME command. RESUME? ... reports the resumed task name, failed command, and remaining command count, then continues the current task.


Planning

SAgent provides a DSL-native plan cursor.

PLAN --new Optional explanation `[>] First step
  multiline detail
[ ] Second step
[ ] Third step
[x] Already completed step
`

Markers:

  • [>] current step;
  • [ ] pending step;
  • [x] completed step.

Multiline step details continue until the next marker.

If no [>] exists, the first [ ] becomes current in memory.

File-backed plan

PLAN --open PLAN.md Optional explanation

or:

PLAN --load PLAN.md Optional explanation

The plan file uses the same marker format:

[>] Investigate current behavior
details may span multiple lines

[ ] Implement file-backed PLAN
[ ] Test synchronization
[x] Old completed step

For file-backed plans:

  • the file is the source of truth;
  • SAgent re-reads it on later dsl calls;
  • manual edits are picked up automatically;
  • PLAN --done is the only command that writes markers back to the file;
  • PLAN --clear only clears the active plan/binding and does not modify the file.

If multiple [>] markers exist, SAgent uses the first as current and treats later current markers as pending in memory. PLAN --done normalizes markers when it writes the file.

Plan commands

PLAN --done Optional explanation
PLAN --clear Optional explanation
PLAN --show --limit N
PLAN --showAll
PLAN --show-all

While a plan is active, later dsl outputs append:

CURRENT_PLAN
2/5: Current step description

When every step is complete, CURRENT_PLAN stops appearing, but the completed plan remains available through PLAN --showAll until cleared.


Web commands

WEB_SEARCH query response_length=short
WEB_IMAGE_SEARCH query response_length=short
WEB_IMG_SEARCH query response_length=short
WEB_OPEN ref_or_url lineno=N
WEB_FIND ref_or_url pattern
WEB key=value ...
WEB `{"open":[{"ref_id":"https://example.com","lineno":5}]}
`

WEB accepts key/value arguments or a raw JSON block.


Image commands

IMAGE_GEN filename `prompt text

`
IMG_GEN filename `prompt text

`
VIEW_IMAGE path
VIEW_IMAGE path detail=original

IMAGE_GEN / IMG_GEN generate PNG images.

VIEW_IMAGE loads a local image for visual inspection.


Golden workflows

Safely refactor a function

READ --outline src/file.ts
READ --def targetFunction src/file.ts
USES targetFunction src --summary
REPLACE src/file.ts --def `export function targetFunction() {
  return "updated"
}
`
RUN `npm test
`

Start a dev server and inspect logs

SH 0 `npm run dev
`
WAIT 10
SH --status
SH --log 1

Later:

SH --log 1
SH --stop 1

Work with a large plan

PLAN --open PLAN.md
READ --outline src/main.ts
RG --summary "createApp" src

After the active step is complete:

PLAN --done implemented parser lookup

Runtime files

The sagent-ai meta package ships the launcher and selects a native package for the current platform:

sagent-ai
├── bin/sagent.js
├── sagent-ai-win   (Windows x64)
└── sagent-ai-linux (Linux x64)

Each native package contains:

bin/sagent
bin/apply_patch
bin/sagent-semantic-index
bin/sagent-semantic-query
bin/rg
bin/system.md
bin/dsl_runtime.mjs

Windows uses the corresponding .exe filenames and also packages bin/codex-sandbox-runner.exe plus its codex-resources helpers. system.md and dsl_runtime.mjs are loaded next to the native binary, semantic sidecars power SEM, and the bundled rg binary powers RG.


Summary

SAgent keeps the Codex foundation and changes the model-facing workflow into a compact script-like protocol.

The result is a coding agent workflow with:

  • fewer tool calls;
  • less JSON overhead;
  • readable command history;
  • reliable batch recovery;
  • structural code navigation and edits;
  • background and interactive process control;
  • passive status feedback;
  • file-backed planning;
  • web and image support.

It is designed for real project work: search, inspect, edit, test, run, recover, and continue.