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.30

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_batch.

Release 2.2.30 is synchronized with the latest upstream Codex, supports the GPT-5.6 model family, and preserves direct dsl_batch access for models whose server metadata otherwise requests code-mode-only tools.

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 quoted 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/npm for installation;
  • Deno in PATH for %% 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 %% form. Only nested dsl.EXEC / dsl.JS are blocked.

EXEC also has direct Deno access to read and write the current project and to use the network. This allows direct npm imports:

const ts = await import("npm:typescript@5");
await Deno.writeTextFile(".agent-dsl/tmp/typescript-version.txt", ts.version);

Deno caches downloads under .agent-dsl/deno-cache and may materialize a Deno-managed node_modules directory for npm: imports. EXEC clears the inherited host environment and exposes only a small synthetic environment for Deno/npm compatibility. Add a comma-separated [deno.exec] env = "HTTP_PROXY,..." allowlist when specific host env vars should be visible to Deno. Direct process spawning is not granted; call await dsl.SH(...) when a script needs shell commands.

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

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

Built-in profiles are:

  • defaultopenai/gpt-5.3-codex-spark, reasoning low;
  • gpt55-lowopenai/gpt-5.5, reasoning low;
  • gpt55-xhighopenai/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 Deno 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.30.

Highlights in this release:

  • 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_batch 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_batch 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_batch 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_batch 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.

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 with %%.

Prefix a command with %%? to make failure a warning and continue the batch.


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
commands to capture...
%% 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_deno_exec
%% CG --ask "Pick files, risks, and NEXT DSL."
start_deno_exec
resolve_profile_attempts
%% CG impact start_deno_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 Deno 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:

    await dsl.PATCH(`--gen src/game/engine.ts --ask "Summarize the change"
    Add a guard for empty enemy waves.
    Keep public signatures unchanged.`);
  • 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 Deno in PATH.


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
deno repl --deny-read --deny-write --deny-net --deny-env --deny-run --deny-ffi --deny-sys --deny-import

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_batch 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_batch 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.ts

Windows uses the corresponding .exe filenames. system.md and dsl_runtime.ts 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.