Skip to main content

sense run <file>

Tokenizes, parses, and executes the file. Exits 0 on success; on any SenseError (see Error Reference) prints SenseError: [line N] ... to stderr and exits 1. A Python RecursionError from a too-deeply-recursive Sense program is caught and reported the same way, not as a raw traceback. If sense isn’t on your PATH, call the module directly:
--dry-run — every action’s .commit()/ .rollback() still runs its real capability/approval checks, but the body that would perform the actual effect is skipped and simulated instead. Prints a leading banner and, after the run finishes, a trailing summary of everything that would have committed:
See Actions: Dry run for exactly what this does and doesn’t cover — in short, action only, never tool, and .commit()/.rollback() return nil instead of a real value since the body never ran.

sense repl

Just typing sense with no subcommand does the same thing — the same convenience bare python has. sense --help/-h still shows the full subcommand list, so discoverability doesn’t suffer.
Type exit or quit to leave, or press Ctrl-D / Ctrl-C.
Sense’s blocks are indentation-sensitive, so the REPL follows the same convention Python’s own REPL uses: a line ending in : opens a block and switches the prompt to ...; a blank line closes the block and executes everything you’ve typed since the last top-level statement.
A single-line statement with no trailing : executes immediately — no need to press enter twice for ordinary lines.

sense test <file|directory>

Runs every test "description": ... block found while executing each discovered file, and prints a PASS/FAIL report plus a summary line:
A directory target is searched for files named test_*.sns or *_test.sns (the same convention pytest uses) — an ordinary example file sitting alongside your tests won’t get swept in. An error outside any test block (a syntax error, or an unhandled exception in ordinary top-level code) prints as ERROR rather than a named FAIL, since it isn’t tied to a specific test description. Exit code 1 if any test failed or any file errored; 0 otherwise, including when zero test files are found (that’s reported, not treated as a failure).

sense fmt <file|directory>

A directory target formats every .sns file found recursively — no naming restriction (unlike sense test’s test_*.sns/*_test.sns convention). Default (no flags) is non-destructive: it prints to stdout and touches nothing on disk. See the dedicated Formatter page for what’s preserved (comments, blank lines), what’s canonicalized (single-rule policy:, requires ordering, inline blocks), and the two guarantees (never changes behavior, idempotent) that back it.

sense inspect <file> [--port PORT]

Runs the file (same as sense run — any top-level print(...)/side effects execute normally), then serves a live, local, browser-based console over the resulting program’s declared surface: every tool, action, agent, memory, skill, and MCP server the file declares, plus the current policy state and a live audit log — rendered as a call tree, indented and breadcrumbed by which agent/tool/action call each event happened inside of, not just a flat chronological list. Unlike a static docs page, every panel is a real “try it out” against the same running Interpreter your file just populated — not a mockup:
1

Tools & Skills

A typed form per parameter; clicking Call runs the tool for real and shows the actual return value or the actual SensePolicyError.
2

Actions

Prepare, Verify, Commit, and (for a reversible action — which, since rollback is mandatory on one, is the only check needed) Rollback as literal buttons — each disabled until the action reaches the state that makes it legal, mirroring the interpreter’s own prepared → verified → committed checks exactly.
3

Agents

Start and Resume buttons on the real agent. A sync agent’s Start blocks until it pauses or completes, same as calling start(agent) from Sense code would — watching it hit pause() and answering it from the browser is the one thing here with no REST/Swagger analog.
4

Memory

A key/value table; a persistent memory’s table adds a history lookup per key (history(key)’s version log).
--port defaults to 4300 (falls through to whatever’s actually available if that port is taken, printing the real URL either way). Stdlib-only — no new dependency, and the console’s own page loads with no network access — the same “doesn’t need the network to work” principle inference("mock", ...) follows for ask(), not something ask() does by itself regardless of provider. --dry-run — the exact same flag sense run has (above), applied to the console: every Commit/Rollback clicked in the browser is simulated, never running the action’s real body. A “DRY RUN” badge is always visible in the topbar so it’s never ambiguous whether a click is real. See Actions: Dry run for exactly what this does and doesn’t cover.
connect_mcp servers are shown read-only — same reason McpTool has no direct call syntax in the language itself.

sense memory-path [file]

Shows where each persistent memory declared in file would actually store its SQLite file — without running the file at all. Parses it (lexer + parser only) and walks the whole AST for every persistent memory declaration, however deeply nested (inside a session/agent/if/… body, not just the top level) — deliberately never executes it, since a real declaration can have a genuine side effect (creating the file, an initial schema) the moment it runs, which a pure “where would this go” query shouldn’t trigger. Each line is labeled explicit path (whatever persistent memory name: "path" gave it, unchanged) or default (see Memory for the exact default-location rule) — default -- via SENSE_MEMORY_DIR specifically when that environment variable is what’s driving the answer. Run with no file to just check the current configuration and see the exact command to change it:
There’s no Sense-specific config file for this — SENSE_MEMORY_DIR is a plain OS environment variable, the same mechanism ANTHROPIC_API_KEY/ OPENAI_API_KEY already use for inference(...).

sense --version

Exit codes

Contributing

Building from source, the project layout, and how to run the test suite are covered in Installation — not repeated here. Inside src/sense_lang/: lexer.py (indentation-tracking scanner), parser.py (recursive-descent parser → AST), ast_nodes.py, environment.py (scoping + delegation/policy/agent-context resolution — see Architecture), interpreter.py (the tree-walking evaluator, builtins, agent threading), values.py, providers.py (ModelProvider + MockModelProvider), formatter.py (sense fmt), inspector.py (sense inspect’s discovery
  • RPC layer), inspector_static/ (sense inspect’s browser console — one static HTML/CSS/JS file, no build step, no CDN), and cli.py itself.
Run the test suite before sending a change:
Every language-level decision in this codebase is expected to be explainable against the Design Order and Non-Goals pages — if a change can’t say what it makes structurally harder to get wrong, or why it needed to be a language feature rather than a library, that’s worth resolving before merging it.

Continue

Formatter

sense fmt’s canonicalization rules and its two guarantees.

Error reference

What the CLI prints for each failure mode.

Architecture

How source text becomes a running program, end to end.