> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sensecode.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# CLI Reference

> sense run, sense repl, and how the project is organized for contributors.

## `sense run <file>`

```bash theme={null}
sense run examples/fib.sns
```

Tokenizes, parses, and executes the file. Exits `0` on success; on any
`SenseError` (see [Error Reference](/reference/errors)) 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:

```bash theme={null}
python -m sense_lang run examples/fib.sns
```

**`--dry-run`** — every [`action`](/safety/actions)'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:

```bash theme={null}
sense run --dry-run examples/action_rollback.sns
```

```txt theme={null}
DRY RUN — no actions will actually commit

state after commit: committed
state after rollback: rolled_back

--- dry run summary ---
[line 12] reversible action 'update_profile' -> prepared
[line 13] reversible action 'update_profile' -> verified
reversible action 'update_profile' -> committed (dry run — body not executed)
[line 17] reversible action 'update_profile' -> rolled_back (dry run — rollback not executed)
```

See [Actions: Dry run](/safety/actions#dry-run-preview-what-would-commit-without-letting-it-happen)
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`

```bash theme={null}
sense repl
```

```txt theme={null}
Sense 0.20.0 — interactive REPL ('exit' to quit)
sense>
```

<Tip>
  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.
</Tip>

Type `exit` or `quit` to leave, or press Ctrl-D / Ctrl-C.

<Warning>
  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.
</Warning>

```txt theme={null}
sense> x = 5
sense> if x > 3:
...        print("big")
...
big
sense>
```

A single-line statement with no trailing `:` executes immediately — no
need to press enter twice for ordinary lines.

## `sense test <file|directory>`

```bash theme={null}
sense test examples/testing.sns      # a file is always run, regardless of name
sense test tests/                     # a directory is searched recursively
```

Runs every [`test "description": ...`](/language/testing) block found while
executing each discovered file, and prints a PASS/FAIL report plus a
summary line:

```txt theme={null}
examples/testing.sns
  PASS  square of a positive number
  PASS  fibonacci base cases
  FAIL  this one is deliberately wrong
        2 squared is 4, not 5 -- this failure is expected

1 file, 5 tests: 4 passed, 1 failed
```

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>`

```bash theme={null}
sense fmt myfile.sns           # print formatted source to stdout
sense fmt myfile.sns --write   # rewrite the file in place
sense fmt src/ --check          # exit 1 if anything under src/ isn't canonical
```

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](/reference/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]`

```bash theme={null}
sense inspect examples/action_rollback.sns
```

```txt theme={null}
Sense Inspector — examples/action_rollback.sns
  http://127.0.0.1:4300
  (Ctrl+C to stop)
```

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`](/ai-native/tool), [`action`](/safety/actions),
[`agent`](/ai-native/agents), [`memory`](/ai-native/memory),
[`skill`](/ai-native/skills), and
[MCP server](/ai-native/mcp) the file declares, plus the current
[policy](/safety/policy) state and a live [audit log](/safety/actions#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:

<Steps>
  <Step title="Tools & Skills">
    A typed form per parameter; clicking Call runs the tool for real and
    shows the actual return value or the actual `SensePolicyError`.
  </Step>

  <Step title="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.
  </Step>

  <Step title="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.
  </Step>

  <Step title="Memory">
    A key/value table; a `persistent memory`'s table adds a history
    lookup per key (`history(key)`'s version log).
  </Step>
</Steps>

`--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](/safety/actions#dry-run-preview-what-would-commit-without-letting-it-happen)
for exactly what this does and doesn't cover.

<Note>
  `connect_mcp` servers are shown read-only — same reason `McpTool` has no
  direct call syntax in the language itself.
</Note>

## `sense memory-path [file]`

```bash theme={null}
sense memory-path examples/persistent_memory_basics.sns
```

```txt theme={null}
ledger: K:\...\examples\ledger.sense_memory.db  (explicit path)
```

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`](/ai-native/sessions)/[`agent`](/ai-native/agents)/`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](/ai-native/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:

```bash theme={null}
sense memory-path
```

```txt theme={null}
SENSE_MEMORY_DIR is not set.
A persistent memory declared with no explicit path resolves to a
'.sense_memory/' folder next to whichever .sns file declares it:
  <that file's own directory>/.sense_memory/<name>.sense_memory.db

Pass a file to see the exact resolved path(s) for what it declares:
  sense memory-path <file.sns>

To change the default, set SENSE_MEMORY_DIR (PowerShell):
  $env:SENSE_MEMORY_DIR = "C:\path\to\wherever"          # this session only
  [Environment]::SetEnvironmentVariable("SENSE_MEMORY_DIR", "C:\path\to\wherever", "User")
                                                          # persists across sessions
```

<Note>
  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(...)`](/ai-native/model-ask-answer).
</Note>

## `sense --version`

```bash theme={null}
sense --version
```

```txt theme={null}
sense 0.20.0
```

## Exit codes

<Frame>
  | Code | Meaning                                                                                                                                                                                                   |
  | ---- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
  | `0`  | Success (`sense test`: also "no test files found"; `sense fmt --check`: nothing would change; `sense inspect`: the console was stopped with Ctrl+C)                                                       |
  | `1`  | A `SenseError`/`RecursionError` was raised (`sense run`/`repl`/`inspect`); any test failed or any file errored (`sense test`); or (`sense fmt --check`) something would change, or a file failed to parse |
</Frame>

## Contributing

Building from source, the project layout, and how to run the test suite
are covered in [Installation](/installation#building-from-source) — 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](/architecture/scoping-and-delegation)),
`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:

```bash theme={null}
pytest -q
```

Every language-level decision in this codebase is expected to be
explainable against the [Design Order](/philosophy/design-order) and
[Non-Goals](/philosophy/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

<CardGroup cols={2}>
  <Card title="Formatter" icon="wand-magic-sparkles" href="/reference/formatter">
    `sense fmt`'s canonicalization rules and its two guarantees.
  </Card>

  <Card title="Error reference" icon="triangle-exclamation" href="/reference/errors">
    What the CLI prints for each failure mode.
  </Card>

  <Card title="Architecture" icon="diagram-project" href="/architecture/pipeline">
    How source text becomes a running program, end to end.
  </Card>
</CardGroup>
