Skip to content

CLI Reference ​

@semanticintent/rune-cli provides two commands for working with Rune binding manifests.

sh
npm install -g @semanticintent/rune-cli

Workflow ​

The typical workflow is a round-trip: extract a manifest from existing source, then validate to see what's missing, then enrich until the manifest is a complete contract.

sh
rune extract src/           # scan source β†’ generate rune.json
rune validate rune.json     # find missing types and intent annotations
# enrich rune.json with type, intent, min/max/enum
rune validate rune.json     # clean β€” manifest is now a cross-layer contract

rune validate ​

Validates a .rune.json binding manifest against the Rune schema.

sh
rune validate <manifest>
rune validate my-app.rune.json
rune validate my-app.rune.json --format json

Options:

OptionDefaultDescription
--format text|jsontextOutput format. json is CI/editor friendly

Exit codes: 0 = valid (warnings may exist), 1 = one or more errors.

Text output:

βœ“ my-app.rune.json β€” valid
  3 warnings
  [RNE006] tasks  binding 'tasks' has no intent annotation
           Bindings without ? intent travel without rationale. Consider adding one.

JSON output:

json
{
  "manifest": "my-app.rune.json",
  "valid": true,
  "errorCount": 0,
  "warningCount": 3,
  "diagnostics": [
    {
      "code": "RNE006",
      "severity": "warning",
      "binding": "tasks",
      "message": "binding 'tasks' has no intent annotation",
      "hint": "Bindings without ? intent travel without rationale."
    }
  ]
}

CI integration:

yaml
# GitHub Actions
- name: Validate Rune manifest
  run: rune validate rune.json --format json

rune extract ​

Scans source files for Rune binding patterns and generates a .rune.json manifest. Zero-friction onboarding for existing Rune-annotated codebases.

sh
rune extract <source>
rune extract src/app.tsx                     # single file
rune extract src/                            # scan directory recursively
rune extract src/ --host html                # force host format
rune extract src/ --out my-app.rune.json     # custom output path

Options:

OptionDefaultDescription
--host auto|html|ts|csharp|sqlautoHost format. auto detects from file extension
--out <file>rune.jsonOutput manifest path

Output:

βœ“ extracted 7 bindings from 3 files
  @ read: 2  ~ sync: 2  ! act: 2  ? intent: 1
  β†’ rune.json
  Run 'rune validate rune.json' to find missing types and intent annotations.

Supported host formats ​

FormatExtensionsPatterns detected
html.html, .mp@id, ~id, !id as attribute names; ?"annotation"
ts.ts, .tsx, .js, .jsxuseRead(), useSync(), useAct(), useIntent()
csharp.cs[RuneState], [RuneComputed], [RuneAction], [RuneIntent("...")]
sql.sqlCOMMENT ON ... IS 'rune:@ ...' annotation convention

Host format details ​

html
<!-- Detected as attribute names and sigil-prefixed values -->
<field ~new-task placeholder="New task…"/>
<button !add-task>Add</button>
<list @tasks><item @item.title /></list>
<screen ?"mobile task list, focus on speed">
ts
// Detected from hook calls in the reference implementation
const tasks     = useRead('tasks')            // β†’ @ tasks
const [v, set]  = useSync('new-task')         // β†’ ~ new-task
const act       = useAct('add-task')          // β†’ ! add-task
useIntent('screen', 'mobile task list')       // β†’ ? screen, with annotation

// host.* patterns also detected
host.read('tasks')
host.sync('new-task', value)
host.act('add-task', handler)
host.recordIntent('screen', 'annotation')
csharp
// Attributes map to rune types, PascalCase β†’ kebab-case
[RuneState]
public string NewTask { get; set; }           // β†’ ~ new-task

[RuneComputed]
public IEnumerable<Task> Tasks { get; }       // β†’ @ tasks

[RuneAction]
public void AddTask(string title) { }         // β†’ ! add-task

// Stacked attributes are handled β€” intent travels with the binding
[RuneState]
[RuneIntent("approved by risk committee")]
public decimal RiskThreshold { get; set; }    // β†’ ~ risk-threshold + intent
sql
-- Use COMMENT ON with 'rune:sigil intent' annotation
COMMENT ON COLUMN tasks.task_title IS 'rune:~ user-entered β€” cleared after add_task';
COMMENT ON COLUMN tasks.task_id    IS 'rune:@ system-assigned β€” do not mutate';
COMMENT ON FUNCTION add_task       IS 'rune:! no-op if title is empty';
COMMENT ON TABLE tasks             IS 'rune:? personal task tracking';

Extract output ​

The manifest generated by rune extract is a valid starting point β€” types and intent annotations are absent until you add them. rune validate tells you exactly what's missing:

sh
rune extract src/ && rune validate rune.json
# β†’ valid, 10 warnings (missing types and intent annotations)

Enrich the manifest, re-validate, and the warnings disappear. The manifest is now a full cross-layer contract.


Diagnostic codes ​

CodeSeverityDescription
RNE001errorInvalid rune type β€” must be @ ~ ! ?
RNE002errorUnknown binding β€” used but not declared in manifest
RNE003errorWrong rune type for binding kind (e.g. args on @)
RNE004errorMissing required field (e.g. intent on ? binding)
RNE005errorConstraint violation β€” min/max on non-number, enum on non-string, min > max
RNE006warningMissing intent annotation or type declaration
RNE007errorManifest does not conform to rune.schema.json structurally

RNE002 and RNE003 are also raised by the LSP in real time as you type.