How it works
PortRuntime.route_prompt() drives the entire flow:
- The prompt is split into lowercase tokens (slashes and hyphens become spaces).
- Each token is checked against three fields for every registered command and tool:
name,source_hint, andresponsibility. - Each field hit increments the score by 1.
- Commands and tools are ranked independently, highest score first.
- The selector guarantees one command and one tool appear in the results first, then fills the remaining slots from the combined leftover list sorted by score.
Scoring in detail
CLI: route
If no tokens match any entry, the output is simply
No mirrored command/tool matches found. and the process exits with status 0.--limit N
Controls the maximum number of matches returned (default: 5). The first two slots are always reserved for the top command and the top tool (if any). The remainder are filled from the combined leftover pool ranked by score descending.
Command vs. tool matches
Commands
Entries sourced from
PORTED_COMMANDS — high-level operations like /bash, /edit, /memory. They map to user-facing slash-commands in the Claude Code surface.Tools
Entries sourced from
PORTED_TOOLS — lower-level execution primitives like bash_tool, read_file, write_file. They are invoked programmatically during agent turns.kind field so callers can tell them apart at a glance.
CLI: bootstrap
bootstrap runs a full session from a single prompt: it routes, executes shims, streams events, and persists a session file.
Build context
build_port_context() is called to capture workspace state (Python file count, archive availability).Run workspace setup
run_setup(trusted=True) collects Python version, platform, test command, and startup steps.Execute shims
The execution registry fires command and tool shims for every matched entry that has a registered executor.
Stream and submit
stream_submit_message() emits structured events (message_start, command_match, tool_match, permission_denial, message_delta, message_stop), then submit_message() records the turn.CLI: turn-loop
turn-loop runs the same routing logic over multiple successive turns.
| Flag | Default | Description |
|---|---|---|
--max-turns N | 3 | Maximum turns to execute |
--structured-output | off | Emit JSON-formatted turn output instead of plain text |
stop_reason is anything other than completed (e.g. max_turns_reached or max_budget_reached).