Skip to content

feat(kilo): author the sandbox block and write global non-root rules - #2480

Merged
dyoshikawa merged 2 commits into
mainfrom
resolve-scrap-issue-2417-kilo-sandbox-global-rules
Jul 29, 2026
Merged

feat(kilo): author the sandbox block and write global non-root rules#2480
dyoshikawa merged 2 commits into
mainfrom
resolve-scrap-issue-2417-kilo-sandbox-global-rules

Conversation

@dyoshikawa

Copy link
Copy Markdown
Owner

Summary

Closes the two remaining actionable gaps of #2417 (gaps 1 and 3 were closed by #2448).

Gap 2 — Kilo sandbox override

KiloPermissionsOverrideSchema gains a sandbox block, authored under the existing tool-scoped kilo override:

{ "kilo": { "sandbox": { "enabled": true, "network": "deny" } } }

It is shallow-merged into the top-level sandbox key of kilo.jsonc (override keys win, unrelated siblings preserved) and the whole block round-trips back into kilo.sandbox on import — it is tool-scoped, so unlike a canonical field it cannot leak into another tool's config.

The scope rule is the substantive part. Upstream honors allowed_hosts and writable_paths from the global config only, and a project config may merely tighten (enabled: true, network: "deny") — a project-level network denial even clears the global destination exceptions. Rather than writing config Kilo would ignore, project scope emits only enabled/network and drops the rest with a warning pointing at --global.

Gap 4 — global non-root rules

KiloRule.getSettablePaths({ global: true }) gains a nonRoot entry. Worth flagging the asymmetry, which is Kilo's rather than ours: the global root instruction file lives under ~/.config/kilo/AGENTS.md, while the global rules directory is ~/.kilo/rules/ — the same .kilo-relative path the skills adapter already uses in both scopes.

No instructions registration accompanies these files, unlike project scope. Kilo auto-discovers every ~/.kilo/rules/*.md on config load, so writing the files is enough; getExtraSharedWritePaths({ global: true }) stays [] and the rules feature touches no global kilo.jsonc. The e2e case asserts that file is not created.

Deferred

Gap 5 (mode-specific rule directories, .kilo/rules-{mode}/) is not implemented and stays deferred. It is a design decision rather than a drift fix: it needs a mode dimension on KiloRule that does not exist today, and no other adapter has one to follow.

Verification

  • pnpm cicheck green.
  • npx vitest run --config vitest.e2e.config.ts src/e2e/e2e-permissions.spec.ts src/e2e/e2e-rules.spec.ts — 200 passed.

Closes #2417

🤖 Generated with Claude Code

cm-dyoshikawa and others added 2 commits July 29, 2026 07:00
Gap 2: KiloPermissionsOverrideSchema gains `sandbox`, shallow-merged into the
top-level `sandbox` key of kilo.jsonc and round-tripped back on import.
Upstream honors allowed_hosts/writable_paths from the global config only and
lets a project config merely tighten, so project scope emits `enabled` and
`network` and drops the rest with a warning rather than writing config Kilo
would ignore.

Gap 4: global scope gains a nonRoot rules directory. Note Kilo's asymmetry —
the global root file is under ~/.config/kilo while the rules directory is
~/.kilo/rules, matching where the skills adapter writes in both scopes. Kilo
auto-discovers those files on config load, so no `instructions` registration
accompanies them and no global kilo.jsonc is touched.

Gap 5 (mode-specific rule directories, .kilo/rules-{mode}/) stays deferred: it
needs a mode dimension on KiloRule that does not exist today.

Closes #2417

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adding sandbox to KiloPermissionsConfigSchema as an object made an existing
kilo.jsonc whose sandbox is not an object throw out of the constructor, failing
the whole Kilo generate over content rulesync does not manage. The schema now
accepts any value and every read site narrows with isPlainObject, matching how
the adapter already treats the rest of the user's file.

Also: skip writing an empty sandbox when project-scope narrowing drops every
authored key, and record why the global rules directory needs no instructions
registration while the project one does — the rules migrator walks a dedicated
globalRulesDirs() on config load, so the two claims describe different
discovery paths rather than contradicting each other.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@dyoshikawa
dyoshikawa merged commit 010d1c7 into main Jul 29, 2026
9 checks passed
@dyoshikawa
dyoshikawa deleted the resolve-scrap-issue-2417-kilo-sandbox-global-rules branch July 29, 2026 14:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug(kilo): a { enabled: false } MCP toggle entry aborts the entire --targets kilo run (+ sandbox block, steps type, global non-root rules)

2 participants