# Commands

Every command prints JSON lines to stdout, one record a line, and the last line has `"ok"`. The exceptions are `help`, `show` without `--json`, and a program's own output under `run`. A consumer reads every line, takes the last as the result, and ignores keys it does not know: new keys are added, existing ones keep their meaning.

| exit | meaning |
|---|---|
| 0 | ok |
| 1 | errors |
| 2 | a stale edit: the code changed since it was read |
| 64 | usage |
| 124 | `run --timeout` ended the program |
| 125 | `run` could not build or start the program |

The contract the commands share, with every error code and receipt field, is [PROTOCOL.md](https://github.com/ovid-sh/ovid/blob/main/docs/PROTOCOL.md). This is `ovid help commands`:

```text
Commands. Each prints JSON lines; the last line has "ok".

ovid check [--facts]
  One {"fact":"error"} line per problem: code, message, id, file, line, col,
  end_line, end_col, source, and when known expected, got, hint. Summary
  last: {"fact":"summary","ok",errors,packages,funcs,revision,ms}.
ovid build [-o out]          default out: <module>/bin/<module name>;
                             _test.ov files are left out (so for run)
  {"ok",output,bytes,syscalls}: syscalls lists the system call numbers the
  program can make (reachable from main, plus startup's mmap, exit, write),
  enough to run it under a filter that allows nothing else.
ovid run [--] [args...]      program stdio and exit code pass through;
                             if the build fails: errors as JSON, exit 125.
  A program run by run or test gets its arguments and stdio and an empty
  environment: none of ovid's own variables reach it.
  run and test execute the program from TMPDIR (else /tmp), or from memory
  where that is missing or noexec and /proc is mounted; if neither works:
  {"ok":false,"error":"run",message,hint}, exit 125 (run) or 1 (test).
  Killed by a signal: exit 128+N and one line on stderr,
  {"ok":false,"error":"killed",signal,exit,at,stack,fault_addr,hint}, with
  at/stack (the statement and its callers) for a fault on Linux.
  --timeout D (5s, 500ms) ends the program: "signal":"timeout", exit 124.
ovid run --json [--timeout D] [--max-output N] [--] [args...]
  captures the output; one last line, and ovid exits 0 if the program ran:
  {"ok":true,"exit":N,"ms",stdout,stderr}; a signal or timeout gives
  "signal" (with at/stack) in place of "exit". Each stream keeps N bytes
  (65536); past that "truncated":true and stdout_bytes/stderr_bytes.
  A build that fails ends {"ok":false,"errors":N}, exit 125.
ovid test [--run substr] [--list]
  {"fact":"test",id,ok,exit,ms,output} per test; a failure that returned a
  value adds "returned_by": the return statements that can produce it;
  if !ovid/test.Eq(io, got, want) { return 1 } also puts "got X, want Y"
  in its output.
  Output past 4000 bytes is cut ("...(truncated)") and "output_bytes" gives
  its full size.
  A crash adds "signal", "at" (the statement that faulted), "stack" (it and
  each call leading to it, innermost first), and for a bad load or store
  "fault_addr"; a hung test reads "signal":"timeout".
  A test the kernel refused memory reads "error":"out_of_memory", exit 71.
  --list prints the tests without running them.
ovid outline [--pkg P] [--all] [--uses] [--offset N] [--limit N]
  Per decl: id, kind, sig, file, line, end_line, hash, and when present
  doc (its doc comment: the // lines directly above it, with no blank line
  between), size (struct bytes), test. --uses adds used_by: {package:
  refs}, so {} is dead code and a decl used by only one other package is a
  candidate to move there. Paged like grep: at most 200 records, and the
  last line says where the next page starts. A name declared twice in a
  package lists each copy where it is, with its own hash and id_copies:N
  (see ovid help ids).
ovid show <id|name>... [--plain] [--json] [--exprs]
  Text: "// kind id file:a-b hash=H in=decl type=T" then the source, with
  "  // @id" after each line where a statement starts (--plain omits them).
  A decl's source starts at its doc comment, and a-b covers it.
  For a statement or expression (a decl with --exprs), one line per
  expression inside it follows: "//   ex:id line:col text  hash=H type=T",
  in source order, outer before inner. --json: {id,kind,file,line,end_line,
  hash,decl,parent,text,sig,type}, plus doc and doc_line (where it starts;
  line is the decl's own first line) for a decl with a doc comment, and
  "exprs":[{id,line,col,text,hash,type}]. Replace one by id to change part
  of a statement.
ovid refs <id|name> [--offset N] [--limit N]
  {id,kind,in,file,line,col,source} per use, in
  source order: the names the checker resolved to it, so a field or local
  spelled like a type, func, or const is not a use of it; last:
  {"ok":true,target,files,by_pkg:{package: n},external} for all the uses,
  and the paging fields for the ones printed.
ovid grep <regexp> [--pkg P] [--std] [--offset N] [--limit N]
  {file,line,col,match,source,decl,stmt} per match (RE2 syntax).
  A match in a doc comment is in that comment's decl.
  Paging, for outline, refs, and grep: at most 200 records unless --limit
  (0: all), starting after --offset; last: {"ok",count,total,offset,
  has_more,next_offset,revision}. count is what was printed, total all there
  is; pass next_offset as --offset for the next page, and if revision has
  changed between pages, start again.
ovid edit <file|-> [--rev REV] [--dry-run] [--require-clean|--allow-broken] [--show]
  [--force]   see: ovid help edit
ovid replace <id> | insert --after <id> | insert --before <id> | append <id>
  | delete <id>   --expect H | --rev REV | --force   [--text-file F] [--dry-run]
  [--require-clean|--allow-broken] [--show]
  One edit op; the text is read from stdin (or F), so a heredoc works:
    ovid replace st:app.main:3 --expect 1f0c9a2b7d4e <<'EOF'
    ovid/io.Stdout(strptr("a \"quoted\" line\n"), strlen("a \"quoted\" line\n"))
    EOF
  Same checks and result as ovid edit. Every op needs a guard: --expect
  (the hash of the node it names), --rev (the module revision), or --force;
  only append <pkg> goes without.
ovid rename <id|name> <new> [--dry-run]
  Rewrites the declaration's name and each use refs lists, nothing else (a
  field, local, comment, or string spelled the same is left alone); refuses
  collisions and changes that add check errors. Like move it takes no
  --expect: it carries no code, is planned from the module as it is, and a
  replay is refused.
ovid move <id|name>... <pkg> [--file pkg/x.ov] [--dry-run]
  Moves funcs, types, or consts (with doc comments) to pkg, creating it if
  needed; requalifies every use and adds the imports files now need.
  Refuses changes that add check errors. Several names move in order, all or
  none: each move is planned in memory over the ones before it, and only
  when all pass are the files written, together; --dry-run writes nothing.
  One receipt per name, then {"ok":true,"moved":[...],"to","written"}.
ovid init <dir> [--name N]   writes ovid.mod, <N>/main.ov, <N>/main_test.ov
ovid dump [--pkg P] [-o file]
  the program as one JSON document, not paged and large (megabytes for a
  few thousand lines): for tools, not for reading. --pkg keeps one package;
  -o writes it to a file and prints {"ok",output,bytes,revision} instead.
  A string literal that is not UTF-8 is "value_hex", not "value".
ovid version                 {commit, dirty, binary (hash of the executable), path}
ovid help [topic|command]    a topic, or the entry above for one command
```
