sigit-code 1.4.1__tar.gz → 1.5.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. {sigit_code-1.4.1 → sigit_code-1.5.1}/.agents/AGENTS.md +64 -12
  2. {sigit_code-1.4.1 → sigit_code-1.5.1}/.github/workflows/ci.yml +4 -0
  3. sigit_code-1.5.1/.github/workflows/release-mcp-registry.yml +79 -0
  4. {sigit_code-1.4.1 → sigit_code-1.5.1}/AGENTS.md +64 -12
  5. {sigit_code-1.4.1 → sigit_code-1.5.1}/CHANGELOG.md +78 -0
  6. {sigit_code-1.4.1 → sigit_code-1.5.1}/CLAUDE.md +64 -12
  7. {sigit_code-1.4.1 → sigit_code-1.5.1}/Cargo.lock +543 -113
  8. {sigit_code-1.4.1 → sigit_code-1.5.1}/Cargo.toml +3 -3
  9. {sigit_code-1.4.1 → sigit_code-1.5.1}/PKG-INFO +2 -2
  10. {sigit_code-1.4.1 → sigit_code-1.5.1}/README.md +26 -1
  11. sigit_code-1.5.1/docs/hooks.md +92 -0
  12. sigit_code-1.5.1/docs/mcp.md +68 -0
  13. sigit_code-1.5.1/examples/settings-with-hooks.toml +49 -0
  14. {sigit_code-1.4.1 → sigit_code-1.5.1}/pypi/pyproject.toml +5 -1
  15. {sigit_code-1.4.1 → sigit_code-1.5.1}/pyproject.toml +5 -1
  16. sigit_code-1.5.1/server.json +39 -0
  17. {sigit_code-1.4.1 → sigit_code-1.5.1}/src/chat.rs +923 -38
  18. sigit_code-1.5.1/src/commands.rs +436 -0
  19. sigit_code-1.5.1/src/frontmatter.rs +200 -0
  20. sigit_code-1.5.1/src/hooks.rs +507 -0
  21. {sigit_code-1.4.1 → sigit_code-1.5.1}/src/main.rs +298 -77
  22. {sigit_code-1.4.1 → sigit_code-1.5.1}/src/mcp.rs +170 -11
  23. {sigit_code-1.4.1 → sigit_code-1.5.1}/src/permissions.rs +179 -18
  24. {sigit_code-1.4.1 → sigit_code-1.5.1}/src/settings.rs +17 -2
  25. {sigit_code-1.4.1 → sigit_code-1.5.1}/src/skills.rs +6 -149
  26. sigit_code-1.5.1/src/subagents.rs +327 -0
  27. {sigit_code-1.4.1 → sigit_code-1.5.1}/src/tools.rs +530 -71
  28. {sigit_code-1.4.1 → sigit_code-1.5.1}/.agents/skills/agent-client-protocol/SKILL.md +0 -0
  29. {sigit_code-1.4.1 → sigit_code-1.5.1}/.agents/skills/ai-assisted-coding/SKILL.md +0 -0
  30. {sigit_code-1.4.1 → sigit_code-1.5.1}/.agents/skills/branding/SKILL.md +0 -0
  31. {sigit_code-1.4.1 → sigit_code-1.5.1}/.agents/skills/run-sigit/SKILL.md +0 -0
  32. {sigit_code-1.4.1 → sigit_code-1.5.1}/.agents/skills/run-sigit/driver.mjs +0 -0
  33. {sigit_code-1.4.1 → sigit_code-1.5.1}/.agents/skills/run-sigit/tui-smoke.sh +0 -0
  34. {sigit_code-1.4.1 → sigit_code-1.5.1}/.agents/skills/sigit-code-release/SKILL.md +0 -0
  35. {sigit_code-1.4.1 → sigit_code-1.5.1}/.agents/skills/tool-calling/SKILL.md +0 -0
  36. {sigit_code-1.4.1 → sigit_code-1.5.1}/.claude/skills/agent-client-protocol/SKILL.md +0 -0
  37. {sigit_code-1.4.1 → sigit_code-1.5.1}/.claude/skills/ai-assisted-coding/SKILL.md +0 -0
  38. {sigit_code-1.4.1 → sigit_code-1.5.1}/.claude/skills/branding/SKILL.md +0 -0
  39. {sigit_code-1.4.1 → sigit_code-1.5.1}/.claude/skills/run-sigit/SKILL.md +0 -0
  40. {sigit_code-1.4.1 → sigit_code-1.5.1}/.claude/skills/run-sigit/driver.mjs +0 -0
  41. {sigit_code-1.4.1 → sigit_code-1.5.1}/.claude/skills/run-sigit/tui-smoke.sh +0 -0
  42. {sigit_code-1.4.1 → sigit_code-1.5.1}/.claude/skills/sigit-code-release/SKILL.md +0 -0
  43. {sigit_code-1.4.1 → sigit_code-1.5.1}/.claude/skills/tool-calling/SKILL.md +0 -0
  44. {sigit_code-1.4.1 → sigit_code-1.5.1}/.github/workflows/release-crates.yml +0 -0
  45. {sigit_code-1.4.1 → sigit_code-1.5.1}/.github/workflows/release-github.yml +0 -0
  46. {sigit_code-1.4.1 → sigit_code-1.5.1}/.github/workflows/release-homebrew.yml +0 -0
  47. {sigit_code-1.4.1 → sigit_code-1.5.1}/.github/workflows/release-npm.yml +0 -0
  48. {sigit_code-1.4.1 → sigit_code-1.5.1}/.github/workflows/release-pypi.yml +0 -0
  49. {sigit_code-1.4.1 → sigit_code-1.5.1}/.gitignore +0 -0
  50. {sigit_code-1.4.1 → sigit_code-1.5.1}/.nvmrc +0 -0
  51. {sigit_code-1.4.1 → sigit_code-1.5.1}/LICENSE +0 -0
  52. {sigit_code-1.4.1 → sigit_code-1.5.1}/examples/skills/README.md +0 -0
  53. {sigit_code-1.4.1 → sigit_code-1.5.1}/examples/skills/commit-message/SKILL.md +0 -0
  54. {sigit_code-1.4.1 → sigit_code-1.5.1}/npm/README.md.tmpl +0 -0
  55. {sigit_code-1.4.1 → sigit_code-1.5.1}/npm/package-main.json.tmpl +0 -0
  56. {sigit_code-1.4.1 → sigit_code-1.5.1}/npm/package.json.tmpl +0 -0
  57. {sigit_code-1.4.1 → sigit_code-1.5.1}/npm/scripts/render-main-package.cjs +0 -0
  58. {sigit_code-1.4.1 → sigit_code-1.5.1}/npm/scripts/render-platform-package.cjs +0 -0
  59. {sigit_code-1.4.1 → sigit_code-1.5.1}/npm/sigit/.gitignore +0 -0
  60. {sigit_code-1.4.1 → sigit_code-1.5.1}/npm/sigit/README.md +0 -0
  61. {sigit_code-1.4.1 → sigit_code-1.5.1}/npm/sigit/package.json +0 -0
  62. {sigit_code-1.4.1 → sigit_code-1.5.1}/npm/sigit/src/index.ts +0 -0
  63. {sigit_code-1.4.1 → sigit_code-1.5.1}/npm/sigit/tsconfig.json +0 -0
  64. {sigit_code-1.4.1 → sigit_code-1.5.1}/pypi/README.md +0 -0
  65. {sigit_code-1.4.1 → sigit_code-1.5.1}/rust-toolchain.toml +0 -0
  66. {sigit_code-1.4.1 → sigit_code-1.5.1}/src/account.rs +0 -0
  67. {sigit_code-1.4.1 → sigit_code-1.5.1}/src/backend.rs +0 -0
  68. {sigit_code-1.4.1 → sigit_code-1.5.1}/src/credentials.rs +0 -0
  69. {sigit_code-1.4.1 → sigit_code-1.5.1}/src/headless.rs +0 -0
  70. {sigit_code-1.4.1 → sigit_code-1.5.1}/src/instructions.rs +0 -0
  71. {sigit_code-1.4.1 → sigit_code-1.5.1}/src/models.rs +0 -0
  72. {sigit_code-1.4.1 → sigit_code-1.5.1}/src/provider.rs +0 -0
  73. {sigit_code-1.4.1 → sigit_code-1.5.1}/src/session_store.rs +0 -0
  74. {sigit_code-1.4.1 → sigit_code-1.5.1}/src/setup.rs +0 -0
  75. {sigit_code-1.4.1 → sigit_code-1.5.1}/tests/acp_permissions.rs +0 -0
  76. {sigit_code-1.4.1 → sigit_code-1.5.1}/tests/headless_mode.rs +0 -0
@@ -110,7 +110,23 @@ feeds results back. Neither the loop nor ACP/TUI surfaces depend on a concrete b
110
110
  spec list (`all_tools`) and the execute `match` (`execute_tool`). `run_command` also enforces
111
111
  commit attribution: when a command creates a new commit that lacks the
112
112
  `Co-Authored-By: siGit Code` trailer (`COMMIT_CO_AUTHOR_TRAILER`), it amends the trailer in —
113
- unless the commit already exists on a remote, which is never rewritten.
113
+ unless the commit already exists on a remote, which is never rewritten. Also owns the `task`
114
+ tool: a nested agent loop in a fresh conversation, offered only when `subagent_available()`
115
+ (a subagent factory is registered — see `register_subagent_factory_for` in `main.rs`; on-device
116
+ registers a `None`-returning factory since onde has a single shared history). A subagent's
117
+ toolset is a hard-gated read-only allow-list (`SUBAGENT_TOOL_NAMES`) that is never expanded by a
118
+ configurable subagent type (see `src/subagents.rs`) — only ever narrowed — so a `.sigit/agents/*.md`
119
+ file can't grant itself `edit_file`/`run_command` and bypass the permission system. Also owns
120
+ `web_search`: a thin native wrapper around the official MCP server's Brave-Search-backed
121
+ `web_search` tool (`mcp__sigit__web_search`, implemented server-side in `sigit-si`'s
122
+ `WebSearchService` + `Mcp::Tools::WebSearch`), offered only when that MCP tool was actually
123
+ discovered (i.e. the user is signed in to siGit Code Cloud — see `web_search_available`).
124
+ Wrapping it natively rather than leaving it as a raw `mcp__*` tool matters for two reasons:
125
+ `permissions::classify` treats every `mcp__*` tool as mutating (an "ask" prompt on every call),
126
+ while `web_search` is read-only like `read_website`; and the raw delegate name is filtered out
127
+ of the assembled tool list (`is_web_search_delegate`) so the model sees one clean option, not
128
+ two names for the same tool. Execution still forwards verbatim to `mcp::call_tool` — no second
129
+ HTTP/JSON-RPC implementation.
114
130
  - **`src/skills.rs`** — [Agent Skills](https://agentskills.io) support. Discovers skill
115
131
  folders (each with a `SKILL.md`: YAML frontmatter `name` + `description`, then Markdown
116
132
  instructions) from `.sigit/skills/` and `.claude/skills/` in the cwd, `$SIGIT_CONFIG_DIR/skills/`,
@@ -119,6 +135,31 @@ feeds results back. Neither the loop nor ACP/TUI surfaces depend on a concrete b
119
135
  calls `skill` with a name) loads the full `SKILL.md` body. The `skill` tool is appended in the
120
136
  `*_as_specs`/`build_tool_specs` layer (not in `all_tools()`) so its description can be dynamic,
121
137
  and only when at least one skill exists.
138
+ - **`src/commands.rs`** — user-defined slash commands. Discovers Markdown files (each an
139
+ optional YAML frontmatter block — `description`, `argument-hint` — followed by a prompt-template
140
+ body) from `.sigit/commands/` and `.claude/commands/` in the cwd, `$SIGIT_CONFIG_DIR/commands/`,
141
+ and `~/.claude/commands/`. A subdirectory namespaces the command with `:`
142
+ (`.sigit/commands/git/commit.md` → `/git:commit`). Unlike skills there's no tool-call
143
+ indirection: invoking one works exactly like the built-in `/init` — `commands::render`
144
+ substitutes `$ARGUMENTS`/`$1..$9` in the body against whatever followed the command on the
145
+ input line, and the result is fed to the model as a normal turn through the ordinary tools and
146
+ permission checks. Resolution happens where each surface (`main.rs`/`chat.rs`) already
147
+ special-cases `/init`: an unrecognized slash command is tried against `commands::resolve_command`
148
+ before falling back to "unknown command". A custom command sharing a name with a built-in is
149
+ unreachable (built-ins match first in `parse_slash`) and is skipped when advertised to ACP
150
+ clients, with a warning logged.
151
+ - **`src/subagents.rs`** — configurable subagent types for the `task` tool. Discovers Markdown
152
+ files (YAML frontmatter `name` + `description`, optional comma-separated `tools:` allow-list,
153
+ then a Markdown body that becomes the subagent's system prompt) from `.sigit/agents/` and
154
+ `.claude/agents/` in the cwd, `$SIGIT_CONFIG_DIR/agents/`, and `~/.claude/agents/`. Passing a
155
+ type's `name` as `task`'s `subagent_type` argument swaps in that system prompt and, if `tools:`
156
+ is set, narrows the offered toolset to its *intersection* with `SUBAGENT_TOOL_NAMES` — the
157
+ security-relevant narrowing logic lives in `tools.rs` next to that constant, not here; this
158
+ module only discovers and parses files. `SubagentFactory` (in `tools.rs`) takes the resolved
159
+ system prompt per call rather than baking one in at registration, so a single registered
160
+ factory serves both the default research subagent and every configured type.
161
+ - **`src/frontmatter.rs`** — shared "YAML frontmatter + Markdown body" parsing used by both
162
+ `src/skills.rs` (`SKILL.md`) and `src/commands.rs` (`.sigit/commands/*.md`).
122
163
  - **`src/mcp.rs`** — [Model Context Protocol](https://modelcontextprotocol.io) *client*. Two
123
164
  transports: **Streamable HTTP** (one JSON-RPC POST endpoint, `url` in `mcp.toml`; replies are
124
165
  `application/json` or SSE) and **stdio** (`command` + optional `args`/`[server.env]` in
@@ -131,12 +172,20 @@ feeds results back. Neither the loop nor ACP/TUI surfaces depend on a concrete b
131
172
  both read it; `/reload` does *not* re-run it, so config changes need a restart. stdio children
132
173
  live for the process; a dead child fails calls with an in-band error string (no auto-restart).
133
174
  Tools are namespaced `mcp__<server>__<tool>`, appended in the `*_as_specs`/`build_tool_specs`
134
- layer and routed in `tools::execute_tool` via `mcp::is_mcp_tool`. The official server
135
- (`<cloud>/mcp`, default `https://sigit.si/api/v1/mcp`) is baked in (always HTTP) and authed
136
- with the cloud session token; extra servers live in `mcp.toml` (global
175
+ layer and routed in `tools::execute_tool` via `mcp::is_mcp_tool`. Two servers are baked in:
176
+ the official server (`<cloud>/mcp`, default `https://sigit.si/api/v1/mcp`, always HTTP, authed
177
+ with the cloud session token) and the smbCloud CLI server (`smb --mcp`, stdio, added only when
178
+ the `smb` binary is on `PATH`; opt out with `smbcloud = false` in `mcp.toml` or
179
+ `SIGIT_MCP_SMBCLOUD=off`). A user-defined entry named `sigit` or `smbcloud` overrides the
180
+ corresponding baked-in one. Extra servers live in `mcp.toml` (global
137
181
  `$SIGIT_CONFIG_DIR/mcp.toml` and project-local `.sigit/mcp.toml`). The stdio path is covered by
138
182
  `tests/mcp_stdio.rs`, driven by the test-only `src/bin/mcp_stdio_stub.rs` helper binary
139
- (excluded from the published crate via `exclude` in `Cargo.toml`).
183
+ (excluded from the published crate via `exclude` in `Cargo.toml`). The baked-in official
184
+ server is *also* listed in the public MCP Registry as `si.sigit/sigit` — a **remote**
185
+ Streamable-HTTP listing (`server.json` at the repo root, published by
186
+ `release-mcp-registry.yml`). Because it's a remote server, the registry's URL-match rule
187
+ forces a domain namespace (`si.sigit` ↔ `sigit.si`) verified by a DNS TXT record, not the
188
+ GitHub-OIDC scheme `smbcloud-cli` uses for its package listing.
140
189
  - **`src/permissions.rs`** — tool permission policy. Every tool call passes through
141
190
  `decision_for` before executing: read-only tools always run; mutating tools (and all
142
191
  `mcp__*`/unknown tools) are governed by, in order: per-session plan mode (`/plan` — deny all
@@ -165,12 +214,14 @@ feeds results back. Neither the loop nor ACP/TUI surfaces depend on a concrete b
165
214
  - **`src/credentials.rs`** — local session-token store (TOML, `0600` on Unix).
166
215
  - **`src/models.rs`** — model-picker types shared across platforms.
167
216
 
168
- Slash commands (`/help`, `/models`, `/skills`, `/mcp`, `/login`, `/logout`, `/whoami`, `/reload`,
169
- `/plan`, `/permissions`, `/init`, `/clear`, `/status`) are advertised via `advertise_commands` in
170
- `main.rs` and handled in both the TUI and ACP sessions. `/init` is special: instead of replying
171
- directly it substitutes `instructions::INIT_PROMPT` for the user text and runs a normal agent
172
- turn that explores the repo and writes (or improves) `AGENTS.md` through the ordinary tools and
173
- permission checks.
217
+ Slash commands (`/help`, `/models`, `/skills`, `/agents`, `/commands`, `/mcp`, `/login`, `/logout`,
218
+ `/whoami`, `/reload`, `/plan`, `/permissions`, `/init`, `/clear`, `/status`) are advertised via
219
+ `advertise_commands` in `main.rs` and handled in both the TUI and ACP sessions. `/init` is
220
+ special: instead of replying directly it substitutes `instructions::INIT_PROMPT` for the user
221
+ text and runs a normal agent turn that explores the repo and writes (or improves) `AGENTS.md`
222
+ through the ordinary tools and permission checks. User-defined commands (see `src/commands.rs`)
223
+ get the same treatment via the `SlashCommand::Unknown` fallback path, so anyone can add their own
224
+ `/name` commands without touching the built-in command list.
174
225
 
175
226
  ## Model cache (macOS)
176
227
 
@@ -190,7 +241,8 @@ verbosity with `RUST_LOG`.
190
241
 
191
242
  `OPENAI_BASE_URL` / `OPENAI_API_KEY` (provider override), `SIGIT_API_URL` (account API base,
192
243
  default `https://sigit.si`), `SIGIT_CLOUD_URL`, `SIGIT_CONFIG_DIR` (default `~/.config/sigit`),
193
- `SIGIT_MODEL`, `SIGIT_MCP` (`off` disables MCP), `SIGIT_MCP_OFFICIAL` (`off` drops the baked-in
244
+ `SIGIT_MODEL`, `SIGIT_MCP` (`off` disables MCP), `SIGIT_MCP_SMBCLOUD` (`off` drops the baked-in
245
+ smbCloud CLI server), `SIGIT_MCP_OFFICIAL` (`off` drops the baked-in
194
246
  server), `SIGIT_PERMISSIONS` (`allow`/`ask`/`deny` — overrides the default permission mode for
195
247
  mutating tools; the escape hatch for clients without permission-request support),
196
248
  `HF_HOME` / `HF_HUB_CACHE`, `RUST_LOG`.
@@ -9,6 +9,10 @@ on:
9
9
  pull_request:
10
10
  workflow_dispatch:
11
11
 
12
+ concurrency:
13
+ group: ci
14
+ cancel-in-progress: true
15
+
12
16
  env:
13
17
  CARGO_TERM_COLOR: always
14
18
 
@@ -0,0 +1,79 @@
1
+ name: MCP Registry Release
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ inputs:
6
+ version:
7
+ description: "Override the version in server.json (e.g. 0.2.0); leave blank to publish as-is"
8
+ required: false
9
+
10
+ # A remote server proves namespace ownership through domain (DNS) verification,
11
+ # not GitHub OIDC: the registry checks a v=MCPv1 TXT record on sigit.si against
12
+ # a request signed with the matching Ed25519 private key. See the MCP Registry
13
+ # doc in the sigit-si repo for the one-time key/DNS setup.
14
+ permissions:
15
+ contents: read
16
+
17
+ jobs:
18
+ publish:
19
+ name: Publish server.json to the MCP Registry
20
+ runs-on: ubuntu-latest
21
+ steps:
22
+ - name: Checkout
23
+ uses: actions/checkout@v6
24
+
25
+ - name: Optionally override the version in server.json
26
+ shell: bash
27
+ run: |
28
+ version="${{ github.event.inputs.version }}"
29
+ if [ -n "${version}" ]; then
30
+ jq --arg v "${version}" '.version = $v' server.json > server.tmp
31
+ mv server.tmp server.json
32
+ fi
33
+ cat server.json
34
+
35
+ - name: Check the remote URL matches the namespace domain
36
+ shell: bash
37
+ run: |
38
+ # The registry rejects a remote server whose URL isn't under the
39
+ # namespace's domain. si.sigit -> sigit.si, so every listed remote
40
+ # must live on sigit.si (or a subdomain).
41
+ server_name="$(jq -r '.name' server.json)"
42
+ domain="$(echo "${server_name%%/*}" | awk -F. '{ for (i=NF; i>=1; i--) printf "%s%s", $i, (i>1 ? "." : "") }')"
43
+ echo "Server: ${server_name} Domain: ${domain}"
44
+
45
+ bad="$(jq -r --arg d "${domain}" '
46
+ .remotes // []
47
+ | map(.url | sub("^[a-z]+://"; "") | sub("/.*$"; ""))
48
+ | map(select(. != $d and (endswith("." + $d) | not)))
49
+ | .[]' server.json)"
50
+ if [ -n "${bad}" ]; then
51
+ echo "Remote URL host(s) not under ${domain}: ${bad}" >&2
52
+ exit 1
53
+ fi
54
+
55
+ - name: Install mcp-publisher
56
+ shell: bash
57
+ run: |
58
+ curl -L "https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_$(uname -s | tr '[:upper:]' '[:lower:]')_$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/').tar.gz" | tar xz mcp-publisher
59
+
60
+ - name: Authenticate to the MCP Registry
61
+ shell: bash
62
+ env:
63
+ MCP_REGISTRY_DNS_PRIVATE_KEY: ${{ secrets.MCP_REGISTRY_DNS_PRIVATE_KEY }}
64
+ run: |
65
+ if [ -z "${MCP_REGISTRY_DNS_PRIVATE_KEY}" ]; then
66
+ echo "MCP_REGISTRY_DNS_PRIVATE_KEY secret is not set. See the MCP Registry doc in the sigit-si repo." >&2
67
+ exit 1
68
+ fi
69
+ ./mcp-publisher login dns --domain=sigit.si --private-key="${MCP_REGISTRY_DNS_PRIVATE_KEY}"
70
+
71
+ - name: Publish
72
+ shell: bash
73
+ run: ./mcp-publisher publish
74
+
75
+ - name: Verify the server is listed
76
+ shell: bash
77
+ run: |
78
+ server_name="$(jq -r '.name' server.json)"
79
+ curl -fsSL "https://registry.modelcontextprotocol.io/v0.1/servers?search=${server_name}" | jq .
@@ -110,7 +110,23 @@ feeds results back. Neither the loop nor ACP/TUI surfaces depend on a concrete b
110
110
  spec list (`all_tools`) and the execute `match` (`execute_tool`). `run_command` also enforces
111
111
  commit attribution: when a command creates a new commit that lacks the
112
112
  `Co-Authored-By: siGit Code` trailer (`COMMIT_CO_AUTHOR_TRAILER`), it amends the trailer in —
113
- unless the commit already exists on a remote, which is never rewritten.
113
+ unless the commit already exists on a remote, which is never rewritten. Also owns the `task`
114
+ tool: a nested agent loop in a fresh conversation, offered only when `subagent_available()`
115
+ (a subagent factory is registered — see `register_subagent_factory_for` in `main.rs`; on-device
116
+ registers a `None`-returning factory since onde has a single shared history). A subagent's
117
+ toolset is a hard-gated read-only allow-list (`SUBAGENT_TOOL_NAMES`) that is never expanded by a
118
+ configurable subagent type (see `src/subagents.rs`) — only ever narrowed — so a `.sigit/agents/*.md`
119
+ file can't grant itself `edit_file`/`run_command` and bypass the permission system. Also owns
120
+ `web_search`: a thin native wrapper around the official MCP server's Brave-Search-backed
121
+ `web_search` tool (`mcp__sigit__web_search`, implemented server-side in `sigit-si`'s
122
+ `WebSearchService` + `Mcp::Tools::WebSearch`), offered only when that MCP tool was actually
123
+ discovered (i.e. the user is signed in to siGit Code Cloud — see `web_search_available`).
124
+ Wrapping it natively rather than leaving it as a raw `mcp__*` tool matters for two reasons:
125
+ `permissions::classify` treats every `mcp__*` tool as mutating (an "ask" prompt on every call),
126
+ while `web_search` is read-only like `read_website`; and the raw delegate name is filtered out
127
+ of the assembled tool list (`is_web_search_delegate`) so the model sees one clean option, not
128
+ two names for the same tool. Execution still forwards verbatim to `mcp::call_tool` — no second
129
+ HTTP/JSON-RPC implementation.
114
130
  - **`src/skills.rs`** — [Agent Skills](https://agentskills.io) support. Discovers skill
115
131
  folders (each with a `SKILL.md`: YAML frontmatter `name` + `description`, then Markdown
116
132
  instructions) from `.sigit/skills/` and `.claude/skills/` in the cwd, `$SIGIT_CONFIG_DIR/skills/`,
@@ -119,6 +135,31 @@ feeds results back. Neither the loop nor ACP/TUI surfaces depend on a concrete b
119
135
  calls `skill` with a name) loads the full `SKILL.md` body. The `skill` tool is appended in the
120
136
  `*_as_specs`/`build_tool_specs` layer (not in `all_tools()`) so its description can be dynamic,
121
137
  and only when at least one skill exists.
138
+ - **`src/commands.rs`** — user-defined slash commands. Discovers Markdown files (each an
139
+ optional YAML frontmatter block — `description`, `argument-hint` — followed by a prompt-template
140
+ body) from `.sigit/commands/` and `.claude/commands/` in the cwd, `$SIGIT_CONFIG_DIR/commands/`,
141
+ and `~/.claude/commands/`. A subdirectory namespaces the command with `:`
142
+ (`.sigit/commands/git/commit.md` → `/git:commit`). Unlike skills there's no tool-call
143
+ indirection: invoking one works exactly like the built-in `/init` — `commands::render`
144
+ substitutes `$ARGUMENTS`/`$1..$9` in the body against whatever followed the command on the
145
+ input line, and the result is fed to the model as a normal turn through the ordinary tools and
146
+ permission checks. Resolution happens where each surface (`main.rs`/`chat.rs`) already
147
+ special-cases `/init`: an unrecognized slash command is tried against `commands::resolve_command`
148
+ before falling back to "unknown command". A custom command sharing a name with a built-in is
149
+ unreachable (built-ins match first in `parse_slash`) and is skipped when advertised to ACP
150
+ clients, with a warning logged.
151
+ - **`src/subagents.rs`** — configurable subagent types for the `task` tool. Discovers Markdown
152
+ files (YAML frontmatter `name` + `description`, optional comma-separated `tools:` allow-list,
153
+ then a Markdown body that becomes the subagent's system prompt) from `.sigit/agents/` and
154
+ `.claude/agents/` in the cwd, `$SIGIT_CONFIG_DIR/agents/`, and `~/.claude/agents/`. Passing a
155
+ type's `name` as `task`'s `subagent_type` argument swaps in that system prompt and, if `tools:`
156
+ is set, narrows the offered toolset to its *intersection* with `SUBAGENT_TOOL_NAMES` — the
157
+ security-relevant narrowing logic lives in `tools.rs` next to that constant, not here; this
158
+ module only discovers and parses files. `SubagentFactory` (in `tools.rs`) takes the resolved
159
+ system prompt per call rather than baking one in at registration, so a single registered
160
+ factory serves both the default research subagent and every configured type.
161
+ - **`src/frontmatter.rs`** — shared "YAML frontmatter + Markdown body" parsing used by both
162
+ `src/skills.rs` (`SKILL.md`) and `src/commands.rs` (`.sigit/commands/*.md`).
122
163
  - **`src/mcp.rs`** — [Model Context Protocol](https://modelcontextprotocol.io) *client*. Two
123
164
  transports: **Streamable HTTP** (one JSON-RPC POST endpoint, `url` in `mcp.toml`; replies are
124
165
  `application/json` or SSE) and **stdio** (`command` + optional `args`/`[server.env]` in
@@ -131,12 +172,20 @@ feeds results back. Neither the loop nor ACP/TUI surfaces depend on a concrete b
131
172
  both read it; `/reload` does *not* re-run it, so config changes need a restart. stdio children
132
173
  live for the process; a dead child fails calls with an in-band error string (no auto-restart).
133
174
  Tools are namespaced `mcp__<server>__<tool>`, appended in the `*_as_specs`/`build_tool_specs`
134
- layer and routed in `tools::execute_tool` via `mcp::is_mcp_tool`. The official server
135
- (`<cloud>/mcp`, default `https://sigit.si/api/v1/mcp`) is baked in (always HTTP) and authed
136
- with the cloud session token; extra servers live in `mcp.toml` (global
175
+ layer and routed in `tools::execute_tool` via `mcp::is_mcp_tool`. Two servers are baked in:
176
+ the official server (`<cloud>/mcp`, default `https://sigit.si/api/v1/mcp`, always HTTP, authed
177
+ with the cloud session token) and the smbCloud CLI server (`smb --mcp`, stdio, added only when
178
+ the `smb` binary is on `PATH`; opt out with `smbcloud = false` in `mcp.toml` or
179
+ `SIGIT_MCP_SMBCLOUD=off`). A user-defined entry named `sigit` or `smbcloud` overrides the
180
+ corresponding baked-in one. Extra servers live in `mcp.toml` (global
137
181
  `$SIGIT_CONFIG_DIR/mcp.toml` and project-local `.sigit/mcp.toml`). The stdio path is covered by
138
182
  `tests/mcp_stdio.rs`, driven by the test-only `src/bin/mcp_stdio_stub.rs` helper binary
139
- (excluded from the published crate via `exclude` in `Cargo.toml`).
183
+ (excluded from the published crate via `exclude` in `Cargo.toml`). The baked-in official
184
+ server is *also* listed in the public MCP Registry as `si.sigit/sigit` — a **remote**
185
+ Streamable-HTTP listing (`server.json` at the repo root, published by
186
+ `release-mcp-registry.yml`). Because it's a remote server, the registry's URL-match rule
187
+ forces a domain namespace (`si.sigit` ↔ `sigit.si`) verified by a DNS TXT record, not the
188
+ GitHub-OIDC scheme `smbcloud-cli` uses for its package listing.
140
189
  - **`src/permissions.rs`** — tool permission policy. Every tool call passes through
141
190
  `decision_for` before executing: read-only tools always run; mutating tools (and all
142
191
  `mcp__*`/unknown tools) are governed by, in order: per-session plan mode (`/plan` — deny all
@@ -165,12 +214,14 @@ feeds results back. Neither the loop nor ACP/TUI surfaces depend on a concrete b
165
214
  - **`src/credentials.rs`** — local session-token store (TOML, `0600` on Unix).
166
215
  - **`src/models.rs`** — model-picker types shared across platforms.
167
216
 
168
- Slash commands (`/help`, `/models`, `/skills`, `/mcp`, `/login`, `/logout`, `/whoami`, `/reload`,
169
- `/plan`, `/permissions`, `/init`, `/clear`, `/status`) are advertised via `advertise_commands` in
170
- `main.rs` and handled in both the TUI and ACP sessions. `/init` is special: instead of replying
171
- directly it substitutes `instructions::INIT_PROMPT` for the user text and runs a normal agent
172
- turn that explores the repo and writes (or improves) `AGENTS.md` through the ordinary tools and
173
- permission checks.
217
+ Slash commands (`/help`, `/models`, `/skills`, `/agents`, `/commands`, `/mcp`, `/login`, `/logout`,
218
+ `/whoami`, `/reload`, `/plan`, `/permissions`, `/init`, `/clear`, `/status`) are advertised via
219
+ `advertise_commands` in `main.rs` and handled in both the TUI and ACP sessions. `/init` is
220
+ special: instead of replying directly it substitutes `instructions::INIT_PROMPT` for the user
221
+ text and runs a normal agent turn that explores the repo and writes (or improves) `AGENTS.md`
222
+ through the ordinary tools and permission checks. User-defined commands (see `src/commands.rs`)
223
+ get the same treatment via the `SlashCommand::Unknown` fallback path, so anyone can add their own
224
+ `/name` commands without touching the built-in command list.
174
225
 
175
226
  ## Model cache (macOS)
176
227
 
@@ -190,7 +241,8 @@ verbosity with `RUST_LOG`.
190
241
 
191
242
  `OPENAI_BASE_URL` / `OPENAI_API_KEY` (provider override), `SIGIT_API_URL` (account API base,
192
243
  default `https://sigit.si`), `SIGIT_CLOUD_URL`, `SIGIT_CONFIG_DIR` (default `~/.config/sigit`),
193
- `SIGIT_MODEL`, `SIGIT_MCP` (`off` disables MCP), `SIGIT_MCP_OFFICIAL` (`off` drops the baked-in
244
+ `SIGIT_MODEL`, `SIGIT_MCP` (`off` disables MCP), `SIGIT_MCP_SMBCLOUD` (`off` drops the baked-in
245
+ smbCloud CLI server), `SIGIT_MCP_OFFICIAL` (`off` drops the baked-in
194
246
  server), `SIGIT_PERMISSIONS` (`allow`/`ask`/`deny` — overrides the default permission mode for
195
247
  mutating tools; the escape hatch for clients without permission-request support),
196
248
  `HF_HOME` / `HF_HUB_CACHE`, `RUST_LOG`.
@@ -1,5 +1,83 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.5.1
4
+
5
+ Makes siGit Code work as an Xcode custom agent, and updates the Onde SDK.
6
+
7
+ ### What changed
8
+
9
+ - Xcode can now run siGit Code as a custom agent. Point it at the binary with
10
+ `--acp` as the argument, and that explicit mode loads the selected on-device
11
+ model on the first prompt, since Xcode's chat has no equivalent of `/load`.
12
+ The README covers the setup, including wiring up `xcrun mcpbridge` in
13
+ `mcp.toml` so the agent can use Xcode's build, test, and project tools
14
+ - MCP calls to the `xcode` server time out after 30 seconds instead of 120, so
15
+ a request Xcode cannot service no longer leaves the prompt looking busy for
16
+ two minutes. String JSON-RPC ids from the bridge are handled too
17
+ - The agent stops repeating itself: a tool call made three times with identical
18
+ arguments now forces a text reply instead of looping
19
+ - Onde SDK bumped to 1.2.2
20
+ - The registry listing in `server.json` matches what sigit.si publishes
21
+
22
+ ## 1.5.0
23
+
24
+ Opens the agent up to user extension: lifecycle hooks, custom slash commands,
25
+ and configurable subagent types. Also adds web search, a Repo tab in the TUI,
26
+ and a baked-in smbCloud MCP server.
27
+
28
+ ### What changed
29
+
30
+ - Hooks let you run shell commands at three points in the agent's lifecycle:
31
+ `session_start`, `pre_tool_use`, and `post_tool_use`, configured under
32
+ `[hooks]` in `settings.toml`. Commands get context through variable
33
+ substitution (`{cwd}`, `{tool_name}`, `{tool_result_len}`) and run in the
34
+ session working directory. A hook that fails is logged and the session
35
+ continues; a hook that hangs is killed on a timeout, along with its whole
36
+ process group
37
+ - User-defined slash commands: drop a Markdown file in `.sigit/commands/` or
38
+ `.claude/commands/` (or the personal `$SIGIT_CONFIG_DIR/commands/` and
39
+ `~/.claude/commands/`) with optional `description` and `argument-hint`
40
+ frontmatter, and the body becomes a prompt template. `$ARGUMENTS` takes the
41
+ whole argument string and `$1`..`$9` the positional words. A subdirectory
42
+ namespaces the command with `:`, so `.sigit/commands/git/commit.md` becomes
43
+ `/git:commit`. They run as ordinary agent turns through the usual tools and
44
+ permission checks, and are advertised to ACP clients like Zed. `/commands`
45
+ lists what was discovered
46
+ - Configurable subagent types for the `task` tool: a Markdown file in
47
+ `.sigit/agents/` or `.claude/agents/` with `name`, `description`, and an
48
+ optional `tools:` allow-list, whose body becomes that subagent's system
49
+ prompt. Pass its name as `subagent_type` to swap the prompt in. The
50
+ `tools:` list can only narrow the subagent's read-only ceiling, never widen
51
+ it, so a config file cannot grant itself `edit_file` or `run_command` and
52
+ route around the permission system. `/agents` lists the discovered types
53
+ - New `web_search` tool, backed by the Brave-Search-backed search on siGit
54
+ Code Cloud's MCP server. It is offered only when you are signed in, and it
55
+ is classified read-only, so searching never triggers a permission prompt
56
+ - The TUI gains a Repo tab, shown when the session's `origin` remote points at
57
+ the sigit.si host. It lists issues and pull requests fetched through the
58
+ official MCP server: Up and Down select, Enter opens a scrollable detail,
59
+ `i`, `p`, Left and Right switch sections, `r` refreshes. The tab is hidden
60
+ and skipped in the cycle for any other remote
61
+ - The smbCloud CLI's stdio MCP server (`smb --mcp`) is now baked in, so
62
+ smbCloud project and deployment tools work with no `mcp.toml` setup. It is
63
+ added only when the `smb` binary is on `PATH`, its read-only tools (`me`,
64
+ `deployments`, `project_list`, `project_show`) skip permission prompts, and
65
+ you can opt out with `smbcloud = false` in `mcp.toml` or
66
+ `SIGIT_MCP_SMBCLOUD=off`
67
+ - siGit Code Cloud's MCP server is now listed in the public MCP Registry as
68
+ `si.sigit/sigit`, published from `server.json` at the repository root
69
+
70
+ ### Fixes
71
+
72
+ - An explicit `deny` rule now applies to read-only first-party tools instead
73
+ of being skipped
74
+ - A subagent type whose `tools:` list resolves to an empty set is rejected
75
+ rather than producing a subagent with no tools
76
+ - Command templates render in a single substitution pass, so an argument that
77
+ contains something like `$1` is no longer re-substituted
78
+ - Frontmatter is stripped with the same leniency it is parsed with
79
+ - The Repo tab's detail view no longer shows stale data after a refresh
80
+
3
81
  ## 1.4.1
4
82
 
5
83
  Two small fixes: correct co-author attribution and a Homebrew tap fix.
@@ -110,7 +110,23 @@ feeds results back. Neither the loop nor ACP/TUI surfaces depend on a concrete b
110
110
  spec list (`all_tools`) and the execute `match` (`execute_tool`). `run_command` also enforces
111
111
  commit attribution: when a command creates a new commit that lacks the
112
112
  `Co-Authored-By: siGit Code` trailer (`COMMIT_CO_AUTHOR_TRAILER`), it amends the trailer in —
113
- unless the commit already exists on a remote, which is never rewritten.
113
+ unless the commit already exists on a remote, which is never rewritten. Also owns the `task`
114
+ tool: a nested agent loop in a fresh conversation, offered only when `subagent_available()`
115
+ (a subagent factory is registered — see `register_subagent_factory_for` in `main.rs`; on-device
116
+ registers a `None`-returning factory since onde has a single shared history). A subagent's
117
+ toolset is a hard-gated read-only allow-list (`SUBAGENT_TOOL_NAMES`) that is never expanded by a
118
+ configurable subagent type (see `src/subagents.rs`) — only ever narrowed — so a `.sigit/agents/*.md`
119
+ file can't grant itself `edit_file`/`run_command` and bypass the permission system. Also owns
120
+ `web_search`: a thin native wrapper around the official MCP server's Brave-Search-backed
121
+ `web_search` tool (`mcp__sigit__web_search`, implemented server-side in `sigit-si`'s
122
+ `WebSearchService` + `Mcp::Tools::WebSearch`), offered only when that MCP tool was actually
123
+ discovered (i.e. the user is signed in to siGit Code Cloud — see `web_search_available`).
124
+ Wrapping it natively rather than leaving it as a raw `mcp__*` tool matters for two reasons:
125
+ `permissions::classify` treats every `mcp__*` tool as mutating (an "ask" prompt on every call),
126
+ while `web_search` is read-only like `read_website`; and the raw delegate name is filtered out
127
+ of the assembled tool list (`is_web_search_delegate`) so the model sees one clean option, not
128
+ two names for the same tool. Execution still forwards verbatim to `mcp::call_tool` — no second
129
+ HTTP/JSON-RPC implementation.
114
130
  - **`src/skills.rs`** — [Agent Skills](https://agentskills.io) support. Discovers skill
115
131
  folders (each with a `SKILL.md`: YAML frontmatter `name` + `description`, then Markdown
116
132
  instructions) from `.sigit/skills/` and `.claude/skills/` in the cwd, `$SIGIT_CONFIG_DIR/skills/`,
@@ -119,6 +135,31 @@ feeds results back. Neither the loop nor ACP/TUI surfaces depend on a concrete b
119
135
  calls `skill` with a name) loads the full `SKILL.md` body. The `skill` tool is appended in the
120
136
  `*_as_specs`/`build_tool_specs` layer (not in `all_tools()`) so its description can be dynamic,
121
137
  and only when at least one skill exists.
138
+ - **`src/commands.rs`** — user-defined slash commands. Discovers Markdown files (each an
139
+ optional YAML frontmatter block — `description`, `argument-hint` — followed by a prompt-template
140
+ body) from `.sigit/commands/` and `.claude/commands/` in the cwd, `$SIGIT_CONFIG_DIR/commands/`,
141
+ and `~/.claude/commands/`. A subdirectory namespaces the command with `:`
142
+ (`.sigit/commands/git/commit.md` → `/git:commit`). Unlike skills there's no tool-call
143
+ indirection: invoking one works exactly like the built-in `/init` — `commands::render`
144
+ substitutes `$ARGUMENTS`/`$1..$9` in the body against whatever followed the command on the
145
+ input line, and the result is fed to the model as a normal turn through the ordinary tools and
146
+ permission checks. Resolution happens where each surface (`main.rs`/`chat.rs`) already
147
+ special-cases `/init`: an unrecognized slash command is tried against `commands::resolve_command`
148
+ before falling back to "unknown command". A custom command sharing a name with a built-in is
149
+ unreachable (built-ins match first in `parse_slash`) and is skipped when advertised to ACP
150
+ clients, with a warning logged.
151
+ - **`src/subagents.rs`** — configurable subagent types for the `task` tool. Discovers Markdown
152
+ files (YAML frontmatter `name` + `description`, optional comma-separated `tools:` allow-list,
153
+ then a Markdown body that becomes the subagent's system prompt) from `.sigit/agents/` and
154
+ `.claude/agents/` in the cwd, `$SIGIT_CONFIG_DIR/agents/`, and `~/.claude/agents/`. Passing a
155
+ type's `name` as `task`'s `subagent_type` argument swaps in that system prompt and, if `tools:`
156
+ is set, narrows the offered toolset to its *intersection* with `SUBAGENT_TOOL_NAMES` — the
157
+ security-relevant narrowing logic lives in `tools.rs` next to that constant, not here; this
158
+ module only discovers and parses files. `SubagentFactory` (in `tools.rs`) takes the resolved
159
+ system prompt per call rather than baking one in at registration, so a single registered
160
+ factory serves both the default research subagent and every configured type.
161
+ - **`src/frontmatter.rs`** — shared "YAML frontmatter + Markdown body" parsing used by both
162
+ `src/skills.rs` (`SKILL.md`) and `src/commands.rs` (`.sigit/commands/*.md`).
122
163
  - **`src/mcp.rs`** — [Model Context Protocol](https://modelcontextprotocol.io) *client*. Two
123
164
  transports: **Streamable HTTP** (one JSON-RPC POST endpoint, `url` in `mcp.toml`; replies are
124
165
  `application/json` or SSE) and **stdio** (`command` + optional `args`/`[server.env]` in
@@ -131,12 +172,20 @@ feeds results back. Neither the loop nor ACP/TUI surfaces depend on a concrete b
131
172
  both read it; `/reload` does *not* re-run it, so config changes need a restart. stdio children
132
173
  live for the process; a dead child fails calls with an in-band error string (no auto-restart).
133
174
  Tools are namespaced `mcp__<server>__<tool>`, appended in the `*_as_specs`/`build_tool_specs`
134
- layer and routed in `tools::execute_tool` via `mcp::is_mcp_tool`. The official server
135
- (`<cloud>/mcp`, default `https://sigit.si/api/v1/mcp`) is baked in (always HTTP) and authed
136
- with the cloud session token; extra servers live in `mcp.toml` (global
175
+ layer and routed in `tools::execute_tool` via `mcp::is_mcp_tool`. Two servers are baked in:
176
+ the official server (`<cloud>/mcp`, default `https://sigit.si/api/v1/mcp`, always HTTP, authed
177
+ with the cloud session token) and the smbCloud CLI server (`smb --mcp`, stdio, added only when
178
+ the `smb` binary is on `PATH`; opt out with `smbcloud = false` in `mcp.toml` or
179
+ `SIGIT_MCP_SMBCLOUD=off`). A user-defined entry named `sigit` or `smbcloud` overrides the
180
+ corresponding baked-in one. Extra servers live in `mcp.toml` (global
137
181
  `$SIGIT_CONFIG_DIR/mcp.toml` and project-local `.sigit/mcp.toml`). The stdio path is covered by
138
182
  `tests/mcp_stdio.rs`, driven by the test-only `src/bin/mcp_stdio_stub.rs` helper binary
139
- (excluded from the published crate via `exclude` in `Cargo.toml`).
183
+ (excluded from the published crate via `exclude` in `Cargo.toml`). The baked-in official
184
+ server is *also* listed in the public MCP Registry as `si.sigit/sigit` — a **remote**
185
+ Streamable-HTTP listing (`server.json` at the repo root, published by
186
+ `release-mcp-registry.yml`). Because it's a remote server, the registry's URL-match rule
187
+ forces a domain namespace (`si.sigit` ↔ `sigit.si`) verified by a DNS TXT record, not the
188
+ GitHub-OIDC scheme `smbcloud-cli` uses for its package listing.
140
189
  - **`src/permissions.rs`** — tool permission policy. Every tool call passes through
141
190
  `decision_for` before executing: read-only tools always run; mutating tools (and all
142
191
  `mcp__*`/unknown tools) are governed by, in order: per-session plan mode (`/plan` — deny all
@@ -165,12 +214,14 @@ feeds results back. Neither the loop nor ACP/TUI surfaces depend on a concrete b
165
214
  - **`src/credentials.rs`** — local session-token store (TOML, `0600` on Unix).
166
215
  - **`src/models.rs`** — model-picker types shared across platforms.
167
216
 
168
- Slash commands (`/help`, `/models`, `/skills`, `/mcp`, `/login`, `/logout`, `/whoami`, `/reload`,
169
- `/plan`, `/permissions`, `/init`, `/clear`, `/status`) are advertised via `advertise_commands` in
170
- `main.rs` and handled in both the TUI and ACP sessions. `/init` is special: instead of replying
171
- directly it substitutes `instructions::INIT_PROMPT` for the user text and runs a normal agent
172
- turn that explores the repo and writes (or improves) `AGENTS.md` through the ordinary tools and
173
- permission checks.
217
+ Slash commands (`/help`, `/models`, `/skills`, `/agents`, `/commands`, `/mcp`, `/login`, `/logout`,
218
+ `/whoami`, `/reload`, `/plan`, `/permissions`, `/init`, `/clear`, `/status`) are advertised via
219
+ `advertise_commands` in `main.rs` and handled in both the TUI and ACP sessions. `/init` is
220
+ special: instead of replying directly it substitutes `instructions::INIT_PROMPT` for the user
221
+ text and runs a normal agent turn that explores the repo and writes (or improves) `AGENTS.md`
222
+ through the ordinary tools and permission checks. User-defined commands (see `src/commands.rs`)
223
+ get the same treatment via the `SlashCommand::Unknown` fallback path, so anyone can add their own
224
+ `/name` commands without touching the built-in command list.
174
225
 
175
226
  ## Model cache (macOS)
176
227
 
@@ -190,7 +241,8 @@ verbosity with `RUST_LOG`.
190
241
 
191
242
  `OPENAI_BASE_URL` / `OPENAI_API_KEY` (provider override), `SIGIT_API_URL` (account API base,
192
243
  default `https://sigit.si`), `SIGIT_CLOUD_URL`, `SIGIT_CONFIG_DIR` (default `~/.config/sigit`),
193
- `SIGIT_MODEL`, `SIGIT_MCP` (`off` disables MCP), `SIGIT_MCP_OFFICIAL` (`off` drops the baked-in
244
+ `SIGIT_MODEL`, `SIGIT_MCP` (`off` disables MCP), `SIGIT_MCP_SMBCLOUD` (`off` drops the baked-in
245
+ smbCloud CLI server), `SIGIT_MCP_OFFICIAL` (`off` drops the baked-in
194
246
  server), `SIGIT_PERMISSIONS` (`allow`/`ask`/`deny` — overrides the default permission mode for
195
247
  mutating tools; the escape hatch for clients without permission-request support),
196
248
  `HF_HOME` / `HF_HUB_CACHE`, `RUST_LOG`.