Instructions for agents working in this standalone CLI repository.
- Never use
--no-verifyunless the user explicitly asks for it. - Activate the Hermit environment before running repo commands that depend on managed tooling:
source ./bin/activate-hermit- Install git hooks when setting up the repo locally:
lefthook install- Build the Rust binary:
just build- Run tests:
just test- Run linting (rustfmt + clippy):
just lint- Run the main verification suite:
just check- Build the
sqpackage artifact:
just build-sq- Inspect the CLI surface directly:
./target/debug/agent-tools --help
./target/debug/agent-tools utils calculate --numbers 2 3 --operation add- Smoke-test the packaged
sqmodule and confirmsqis using the localsqbin/output:
just package-smoke
sq which agent-tools
sq agent-tools linear --help
./sqbin/agent-tools.exoskeleton linear --helpsq which agent-tools should point at the package-local sqbin/agent-tools.exoskeleton. If sq agent-tools <extension> ... prints synthesized submenu help instead of the exoskeleton output, compare against ./sqbin/agent-tools.exoskeleton <extension> ... to distinguish outer sq wrapper behavior from bl-cli behavior.
src/kgoose.rsdefines the kgoose ToolEndpoint client and re-exports the generated proto request/response types used by the CLI.src/cli.rsbootstraps global flags and builds the dynamic clap command tree. Parsing is two-phase: a hand-rolled bootstrap parser strips infrastructure flags and extractscommand_tokensfirst, then only the named extension is loaded from the API before building the clap tree. This avoids loading all extensions upfront.src/runtime.rsloads extension/tool metadata from the live kgoose API and derives CLI parameters from tool schemas.src/catalog.rsmanages the static extensions catalog (extensions.yaml), embedded at compile time.src/main.rswires help/version output and live ToolEndpoint execution.src/proto.rsre-exports the generated prost modules and includes thepbjson-buildserde impls used for JSON-over-HTTP decoding of proto-backed request/metadata types.sqbin/agent-tools.exoskeletonis the packaged executable built byjust build-sq.docs/sq-overview.mdcovers the repo and packaged CLI at a high level.docs/sq-integration.mdcovers howsqdiscovers and integrates the packaged module.docs/RELEASING-sq.mdcovers the Homebrew-backedsqcommand-pack release path.docs/RELEASING-bl.mdcovers buildingbland the current distribution status.
External docs: https://clig.dev/llms.txt -> guide you can consult to write better command-line programs, taking traditional UNIX principles and updating them for the modern day.
- This repo is packaged as a single
sqmodule namedagent-tools.exoskeleton. - Homebrew packaging should install the entire
sqbin/directory intoprefix/"etc"sosqcan discover the pack. sqpicks up the repo-local package whensq which agent-toolsresolves tosqbin/agent-tools.exoskeleton.sqsynthesizes extension submenu help from--describe-commandsmetadata. In practice, extension-level flags such assq agent-tools <extension> --helpandsq agent-tools <extension> --describecan be intercepted by the outersqwrapper instead of reaching the exoskeleton.- To verify exoskeleton-specific extension behavior, prefer
./sqbin/agent-tools.exoskeleton <extension> --helpand./sqbin/agent-tools.exoskeleton <extension> --describe, then compare withsq agent-tools <extension> ...to identify wrapper behavior. - The current CLI talks directly to the kgoose ToolEndpoint JSON-over-HTTP routes and expects
KGOOSE_BASE_URL,KGOOSE_PLAYPEN, or explicit flags when needed.GOOSEMCP_PLAYPENis an independent opt-in that adds anenvoy-route--goosemcp=playpen-<name>entry to the outboundBaggageheader for routing the downstream goosemcp Envoy; only set it when a matching playpen pod is running, otherwise extension calls fail with an opaque 5xx. - Prefer generated proto types over handwritten mirrors.
tonic_prost_buildgenerates the prost messages,extern_pathmaps thegoogle.protobufJSON value types topbjson_types, andpbjson-buildadds serde support for the JSON-over-HTTP endpoints so the Rust types stay aligned with the service protos. CallToolResponseis now proto-backed too.src/main.rspretty-prints the typed response envelope directly.- The CLI is dynamic at three levels: ListExtensions determines which top-level extensions exist, ListTools determines which tool subcommands exist under each extension, and each tool's schema determines its flags/options.
- We take a hybrid static/dynamic approach:
- Top-level extensions are static.
extensions.yamlis generated from two sources (kGoose ListExtensionsGrpcAction + G2 web app OAuth config for late-init extensions like notion, asana), then manually curated. Runjust update-extensions-catalogto regenerate. This lets all known extensions appear in--helpeven if the user hasn't connected them yet. - Extension subcommands are fully dynamic. ListTools and CallTool hit the live kgoose API. If the user hasn't connected an extension,
--helpfor that extension will fail with a "not connected" error pointing to G2 Connections. The static catalog is used only to produce helpful error messages (distinguishing "unknown extension" from "known but not connected"). --describe-commandsleaf node is the extension subcommand. We don't return nested tool commands under an extension, sosqforwards args to the extension subcommand directly.
- Top-level extensions are static.