feat(kilo): author the sandbox block and write global non-root rules - #2480
Merged
dyoshikawa merged 2 commits intoJul 29, 2026
Merged
Conversation
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
deleted the
resolve-scrap-issue-2417-kilo-sandbox-global-rules
branch
July 29, 2026 14:25
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes the two remaining actionable gaps of #2417 (gaps 1 and 3 were closed by #2448).
Gap 2 — Kilo sandbox override
KiloPermissionsOverrideSchemagains asandboxblock, authored under the existing tool-scopedkilooverride:{ "kilo": { "sandbox": { "enabled": true, "network": "deny" } } }It is shallow-merged into the top-level
sandboxkey ofkilo.jsonc(override keys win, unrelated siblings preserved) and the whole block round-trips back intokilo.sandboxon 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_hostsandwritable_pathsfrom 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 onlyenabled/networkand drops the rest with a warning pointing at--global.Gap 4 — global non-root rules
KiloRule.getSettablePaths({ global: true })gains anonRootentry. 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
instructionsregistration accompanies these files, unlike project scope. Kilo auto-discovers every~/.kilo/rules/*.mdon config load, so writing the files is enough;getExtraSharedWritePaths({ global: true })stays[]and the rules feature touches no globalkilo.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 onKiloRulethat does not exist today, and no other adapter has one to follow.Verification
pnpm cicheckgreen.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