-
Notifications
You must be signed in to change notification settings - Fork 0
Intent Contract
The intent contract defines the JSON structure the Ollama model must return and the Python router validates before executing any action.
The model never executes commands directly. The router only executes what the intent contract allows.
The formal JSON Schema is at schemas/intent.schema.json.
Every valid intent must include:
{ "schema": "mq-hal.intent.v1" }Intents with a missing or incorrect schema field are rejected.
{
"schema": "mq-hal.intent.v1",
"intent": "git_status",
"repo": "macos-scripts",
"command": null,
"args": [],
"message": "Visar git status."
}| Field | Type | Required | Description |
|---|---|---|---|
schema |
string | Yes | Must be mq-hal.intent.v1
|
intent |
string | Yes | Routed action — see intent types below |
repo |
string or null | Yes | Repo key from config/repos.json, or null |
command |
string or null | Yes |
run_mqlaunch subcommand; null otherwise |
args |
string array | Yes | Arguments for the routed command |
message |
string | Yes | Human-readable description of the action |
Additional properties are rejected.
| Intent | Description |
|---|---|
help |
Print mq-hal command reference |
list_repos |
List configured repos |
print_cd |
Print repo path (for shell cd alias) |
pwd |
Print active repo working directory |
repo_tree |
List files under the active repo |
git_status |
Run git status --short in target repo |
git_log |
Run git log --oneline -n 8 in target repo |
grep_repo |
Run rg -n -- <query> in target repo |
repo_status_json |
Structured inspect and doctor JSON |
| Intent | Description |
|---|---|
switch_repo |
Set active repo in ~/.mq-hal/state.json
|
| Intent | Description |
|---|---|
run_test |
Run the detected safe test command |
open_editor |
Open a file under the repo in $EDITOR
|
run_mqlaunch |
Run an allowlisted mqlaunch command |
| Intent | Description |
|---|---|
create_branch |
Create a branch with git checkout -b
|
| Intent | Description |
|---|---|
refuse |
Refuse the prompt — no execution occurs |
For run_mqlaunch, the command field must match one of:
doctor
release-check
selftest
perf
system-check
demo
Unknown mqlaunch commands are rejected with exit code 2.
Any model output where intent is not in the allowlist is normalized to
refuse by the router before execution.
If the model returns non-JSON or unparseable JSON, the router falls back
to refuse. Execution does not occur.
For intents that resolve a file path (e.g. open_editor), paths outside
the target repo are rejected with exit code 2.
If repo is not a key in config/repos.json, the router falls back to
the active repo from state. It does not error.
For create_branch, branch names are validated with a strict allowlist:
alphanumeric, ., _, -, /. Names starting with -, /, or .
are rejected.
| Condition | Result |
|---|---|
| Unknown intent value | Normalized to refuse
|
| Missing required field | Intent treated as refuse
|
| Non-JSON model output | Router returns refuse
|
| Unknown mqlaunch command | Rejected, exit 2 |
| Path outside repo | Rejected, exit 2 |
| Invalid branch name | Rejected, exit 2 |
When Ollama is unavailable or --no-ai is passed, the router uses a
deterministic local matcher instead of the model. The matcher recognizes
common Swedish and English prompt patterns:
| Trigger | Routed intent |
|---|---|
help, hjälp, --help
|
help |
lista repo, list repos, vilka repo
|
list_repos |
Starts with hitta, sök, search, grep
|
grep_repo |
Starts with öppna, open
|
open_editor |
skapa branch, ny branch, create branch
|
create_branch |
repo-status-json, inspect json
|
repo_status_json |
git status, status
|
git_status |
git log, senaste commit, commits
|
git_log |
träd, tree, filer
|
repo_tree |
kör tester, run tests, testerna
|
run_test |
Any ALLOWED_MQLAUNCH key substring |
run_mqlaunch |
If no pattern matches, the router dies with an error. It does not guess. The intent contract is identical for both paths — the schema version, field structure, and safety rules are the same regardless of whether Ollama or the deterministic matcher produced the intent.
{"schema":"mq-hal.intent.v1","intent":"git_status","repo":"macos-scripts","command":null,"args":[],"message":"Visar git status."}{"schema":"mq-hal.intent.v1","intent":"run_mqlaunch","repo":null,"command":"doctor","args":[],"message":"Kör mqlaunch doctor."}{"schema":"mq-hal.intent.v1","intent":"grep_repo","repo":"mq-hal","command":null,"args":["OLLAMA_MODEL"],"message":"Söker."}{"schema":"mq-hal.intent.v1","intent":"create_branch","repo":"mq-hal","command":null,"args":["feature/hal-router"],"message":"Skapar branch."}Unknown action — normalized to refuse:
{"schema":"mq-hal.intent.v1","intent":"rm_rf","repo":null,"command":null,"args":[],"message":""}Unknown mqlaunch command — rejected with exit 2:
{"schema":"mq-hal.intent.v1","intent":"run_mqlaunch","repo":null,"command":"rm -rf /","args":[],"message":""}Path escape — rejected with exit 2:
{"schema":"mq-hal.intent.v1","intent":"open_editor","repo":"mq-hal","command":null,"args":["../../etc/passwd"],"message":""}