- implement toml configuration parsing
- implement markdown agent/skill parsing from
.claude/and.opencode/ - implement openai api streaming client
- implement cli main loop (stdin, api request, stdout/stderr streams)
- add unified client type config (openai/openai_responses/anthropic/etc)
- add tracing support for verbose logging
- add bash tool with wildcard permission matching
- consolidate permission checking across tools
- add --system-prompt (-s) flag for overriding the system prompt
- gitignore-style glob patterns for permissions (*, **, ?)
- implement "ask" permission with /dev/tty user confirmation
- bash metacharacter fallback to catch-all permission
- --yes flag for auto-accepting ask prompts
- --tools takes comma-separated list (exclusive override)
- --skills flag for exclusive skill override
- --list-agents, --list-skills, --list-tools, --list-providers (with descriptions)
- path mode vs command mode for glob matching
- --dry-run flag to inspect prompts without calling LLM
- --skills flag for exclusive skill override
- show usage on empty prompt (exit non-zero)
- fix find_all_in_dirs double-nesting base directories for global paths
- hook protocol (partial conformance, see the hcp-spec and DESIGN.md):
- discover hooks from
hooks/under existing base dirs (.claude/.opencode/.agents, plus globals) -
discoverstage at startup: register hook tools (<prefix>_<tool_name>) -
mutate_requeststage: merge returnedsystemstrings into the system prompt; payload includes finalized system/user/model/tools -
execute_toolstage: route invocations of hook-registered tools back to the owning script -
before_tool/after_toolstages around built-inread/bashand hook-registered tools, withdeny/args/resultmutation responses -
before_stoppost-loop observational stage withexit_reason/final/error - honor
permission.argfor hook tools (route through existingcheck_tool_permission) -
--list-hooksflag - hook tools appear in
--list-tools - typed parameters: validate args (required, type, enum) before
execute_tool; normalizeanytype - dry-run inclusion of hooks (own section + tools/permissions list)
- host capability payload (
{name, version, stages}) on every hook invocation
- discover hooks from
- hook protocol, tier 1/2 follow-ups:
-
before_stop.continuere-entry into the agent loop (wire format honored; needs plumbing user-prompt re-injection back intorun_agent_stream) -
max_turnsdistinction inbefore_stop.exit_reason(today everything reports"stop"or"error"; needs rig surfacing the loop-exit cause) -
before_turn/after_turnstages -
on_error/on_permissionstages
-
-
--dump-request(-D) flag emits exact OpenAI chat-completions JSON request body -
make precommittarget (lint + test + build) - configurable tool-call output truncation (stderr display); full content spooled to
$XDG_CACHE_HOME/hrns/<pid>/<seq>.txtwith a clear warning -
readtool: optionaloffset(0-indexed line) andcount(number of lines) parameters - config
default_system_promptused when no-sand no agent body
lift hrns's agent loop into a reusable hrns-core library so hmux can drive it in-process as its
most capable backend (../hmux ROADMAP phase 34). the CLI keeps working as a second consumer; no
behavior change. the airun -> hrns rename was a SEPARATE atomic step done at the hmux 34e cutover -
the repo/crate/config/binary names all became hrns (a hard cutover, no old-path fallback).
- convert to a cargo workspace:
hrns-core(lib) +hrns(bin, a root package that is also the workspace). the bin keeps its src/ + tests/ + example toml in place.maketargets now run--workspaceso the core crate's tests + clippy run too. - move the HCP-agnostic, tty-agnostic core into the lib: config (config.rs), glob (glob.rs), the
permission model (permission.rs), agent/skill/markdown resolution (resolve.rs), the built-in
read/bash tools (tools.rs), and the rig agent loop (agent.rs) -- with all their unit tests. a
catalog()of providers+models is deferred to hmux 34b (its shape follows the hmux manifest; hrns's config carries no per-provider model list). - core stays HCP-AGNOSTIC: the HCP host (src/hooks.rs, the v3 hcp-spec host) stays BIN-SIDE and
imports the permission bits from
hrns_core. hmux hosts HCP at the hub layer (its hcp face), so a core-embedded host would double-host an hmux-driven session. - seam
Observer(agent.rs): the loop reports text/reasoning/tool events through it instead of printing; the CLI'sStdioObserverreproduces the stdout/stderr rendering (incl. spool + truncation) verbatim. hmux maps each call to a normalized hub event. - seam
PermissionResolver: the "ask" branch of check_tool_permission takes a&dyn PermissionResolver; the CLI suppliesTtyResolver(/dev/tty + --yes). SYNC for now (the CLI blocks on tty, preserving behavior); async-ified when the hmux impl lands (34b). - seam
ToolMiddleware(tools.rs): before/after-tool + the gated hook-registered tool set. the CLI'sHcpMiddlewareadapts src/hooks.rs onto it; hmux adapts its interceptor bridge. (system- prompt mutation stays a direct main->HCPmutate_request; before_stop stays a direct main->HCP call on the exit inforunreturns.) - seam: history in/out.
runtakeshistory: Vec<ChatMessage>in and returnsRunOutcome { exit_reason, exit_error, history }, using rigstream_chat(prompt, &history)+FinalResponse.history()to accumulate;ChatMessage(= rig Message) +RunOutcomere-exported. the core stays sessionless; the hmux backend stores the Vec per session for follow-up turns. - the caller-supplied seams
PermissionResolver+ToolMiddlewarewent ASYNC (#[async_trait], new dep async-trait);check_tool_permissionis async and the tools await it. the CLI'sTtyResolver/HcpMiddlewareare async but behavior-preserving (blocking tty/subprocess inside async, as before); the hmuxInterceptorResolverawaitsinterceptor.raisefor the native gate. -
resolve_provider(a<provider>/<model>string + Config -> rig client wiring) added to hrns-core, shared by the CLI and the hmux backend (DRY). - seam: a CancellationToken for abort + a steer channel (for hmux steering, 34c). still pending; best built alongside the hmux abort/steer work.
- keep
make precommitgreen: all rust tests pass -- 18 bin + 23 integration + 20 core = 61 -- and 53/53 python conformance checks pass. the HCP host was upgraded v2 -> v3 (host.version=3 + the base payload carries the workspacecwd, echoed by hooks as<hcp-cwd>), closing the two previously-failing conformance checks.