Skip to content

Commit e825113

Browse files
fix: commit remaining configuration schema enhancements and validation logic
1 parent 9db3309 commit e825113

8 files changed

Lines changed: 214 additions & 40 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,4 @@ node_modules/
6464
# Misc
6565
*.tmp
6666
*.temp
67+
GEMINI.md

AGENTS.md

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# kimiko Context
2+
> **Auto-Generated:** 2026-06-12 | **Primary Sources:** Makefile, README.md, validator/requirements.txt, scripts/activate-mandate.sh, docs/AGENTS.md
3+
4+
## 1. System Identity
5+
| Attribute | Value | Source |
6+
| :--- | :--- | :--- |
7+
| Language | Python (3.11+), Shell, PowerShell, Make | Source: README.md:L46-L64 |
8+
| Runtime | Python, Bash, PowerShell | Source: README.md:L44-L64 |
9+
| Framework || Source: — |
10+
| Package Manager | pip | Source: validator/requirements.txt |
11+
| Build System | Make | Source: Makefile:L1-L3 |
12+
13+
## 2. Operational Commands
14+
| Intent | Command (Exact) | Working Dir | Notes | Source |
15+
| :--- | :--- | :--- | :--- | :--- |
16+
| Install | `make install` | Root | Platform-aware installation | Source: Makefile:L160-L174 |
17+
| Test | `make test` | Root | Runs pytest suite for validator | Source: Makefile:L350-L357 |
18+
| Lint | `make check` | Root | Validates configuration | Source: Makefile:L325-L341 |
19+
| Verify | `make verify` | Root | Checks installation files | Source: Makefile:L359-L406 |
20+
| Uninstall | `make uninstall`| Root | Removes Kimiko-managed files | Source: Makefile:L310-L318 |
21+
| Deps | `make deps` | Root | Installs Python dependencies | Source: Makefile:L321-L323 |
22+
23+
## 3. Architecture & Conventions
24+
| Concern | Value | Source |
25+
| :--- | :--- | :--- |
26+
| Entrypoint / Bootstrap | `scripts/launch-with-mandate.sh` | Source: Makefile:L266-L271; docs/AGENTS.md:L189-L194 |
27+
| Routing || Source: — |
28+
| State Management | `kimi.json` and config files deployed to `~/.kimi-code/` | Source: docs/AGENTS.md:L245-L251 |
29+
| Styling || Source: — |
30+
| Testing | `pytest` | Source: validator/requirements.txt:L3; Makefile:L356 |
31+
| Linting / Formatting | `ruff` | Source: validator/requirements.txt:L4 |
32+
| Error Handling / Logging | Session logs in `~/.kimi-code/logs/` | Source: docs/AGENTS.md:L39-L40 |
33+
34+
## 4. Environment Variables
35+
| Variable | Required | Description | Where Set/Validated | Source |
36+
| :--- | :---: | :--- | :--- | :--- |
37+
| `KIMI_GLOBAL_CONFIG` | Yes || `scripts/activate-mandate.sh` | Source: scripts/activate-mandate.sh:L29 |
38+
| `KIMI_MANDATE_ACTIVE` | Yes || `scripts/activate-mandate.sh` | Source: scripts/activate-mandate.sh:L30 |
39+
| `KIMI_ADMIN_MODE` | Yes || `scripts/activate-mandate.sh` | Source: scripts/activate-mandate.sh:L31 |
40+
| `KIMI_ZERO_BLOCKERS` | Yes || `scripts/activate-mandate.sh` | Source: scripts/activate-mandate.sh:L32 |
41+
| `KIMI_DEFAULT_YOLO` | Yes || `scripts/activate-mandate.sh` | Source: scripts/activate-mandate.sh:L33 |
42+
| `KIMI_SKIP_AFK_INJECTION` | Yes || `scripts/activate-mandate.sh` | Source: scripts/activate-mandate.sh:L34 |
43+
44+
## 5. Critical Files Map
45+
| Path | Purpose | Source |
46+
| :--- | :--- | :--- |
47+
| `Makefile` | Main build/install configuration | Source: Makefile:L1-L444 |
48+
| `scripts/activate-mandate.sh` | Bash script to enforce mandate in session | Source: scripts/activate-mandate.sh:L1-L106 |
49+
| `validator/validate_kimi.py` | Validates config structure and rules | Source: Makefile:L333-L339; docs/AGENTS.md:L308-L328 |
50+
| `config/config.toml` | Main Kimi CLI config template | Source: docs/AGENTS.md:L170-L173 |
51+
| `docs/AGENTS.md` | System-level mandate directory and enforcement docs | Source: docs/AGENTS.md:L1-L425 |
52+
53+
## 6. Gaps & Negative Evidence
54+
| Missing Item | Where You Looked | Result |
55+
| :--- | :--- | :--- |
56+
| Node.js / NPM | `.nvmrc`, `package.json`, `Makefile` | Not found |
57+
| Python version pin | `pyproject.toml`, `.python-version`, `requirements.txt` | No strict pin found |

config/config.toml

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ default_plan_mode = false
55
default_editor = ""
66
theme = "gruvbox-dark"
77
show_thinking_stream = true
8-
hooks = []
98
merge_all_available_skills = true
109
extra_skill_dirs = []
1110
telemetry = false
1211
default_model = "kimi-code/kimi-for-coding"
12+
default_permission_mode = "manual"
1313

1414
[loop_control]
1515
max_steps_per_turn = 1000
@@ -34,21 +34,6 @@ print_wait_ceiling_s = 3600
3434
[notifications]
3535
claim_stale_after_ms = 15000
3636

37-
[services.moonshot_search]
38-
base_url = "https://api.kimi.com/coding/v1/search"
39-
api_key = ""
40-
41-
[services.moonshot_search.oauth]
42-
storage = "file"
43-
key = "oauth/kimi-code"
44-
45-
[services.moonshot_fetch]
46-
base_url = "https://api.kimi.com/coding/v1/fetch"
47-
api_key = ""
48-
49-
[services.moonshot_fetch.oauth]
50-
storage = "file"
51-
key = "oauth/kimi-code"
5237

5338
[mcp.client]
5439
tool_call_timeout_ms = 60000
@@ -1165,9 +1150,6 @@ type = "kimi"
11651150
api_key = ""
11661151
base_url = "https://api.kimi.com/coding/v1"
11671152

1168-
[providers."managed:kimi-code".oauth]
1169-
storage = "file"
1170-
key = "oauth/kimi-code"
11711153

11721154
[models."kimi-code/kimi-for-coding"]
11731155
provider = "managed:kimi-code"
@@ -1181,3 +1163,20 @@ goal_command = true
11811163
micro_compaction = true
11821164
background_ask = true
11831165
sub_skill = true
1166+
1167+
[thinking]
1168+
mode = "auto"
1169+
1170+
[[permission.rules]]
1171+
decision = "allow"
1172+
pattern = "Read"
1173+
1174+
[[permission.rules]]
1175+
decision = "deny"
1176+
pattern = "Bash(rm -rf*)"
1177+
1178+
[[hooks]]
1179+
event = "PreToolUse"
1180+
matcher = "Bash"
1181+
command = "node ~/.kimi-code/hooks/check-bash.mjs"
1182+
timeout = 5

config/kimi.toml

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ default_plan_mode = false
55
default_editor = ""
66
theme = "gruvbox-dark"
77
show_thinking_stream = true
8-
hooks = []
98
merge_all_available_skills = true
109
extra_skill_dirs = []
1110
telemetry = false
1211
default_model = "kimi-code/kimi-for-coding"
12+
default_permission_mode = "manual"
1313

1414
[loop_control]
1515
max_steps_per_turn = 1000
@@ -34,21 +34,6 @@ print_wait_ceiling_s = 3600
3434
[notifications]
3535
claim_stale_after_ms = 15000
3636

37-
[services.moonshot_search]
38-
base_url = "https://api.kimi.com/coding/v1/search"
39-
api_key = ""
40-
41-
[services.moonshot_search.oauth]
42-
storage = "file"
43-
key = "oauth/kimi-code"
44-
45-
[services.moonshot_fetch]
46-
base_url = "https://api.kimi.com/coding/v1/fetch"
47-
api_key = ""
48-
49-
[services.moonshot_fetch.oauth]
50-
storage = "file"
51-
key = "oauth/kimi-code"
5237

5338
[mcp.client]
5439
tool_call_timeout_ms = 60000
@@ -1165,9 +1150,6 @@ type = "kimi"
11651150
api_key = ""
11661151
base_url = "https://api.kimi.com/coding/v1"
11671152

1168-
[providers."managed:kimi-code".oauth]
1169-
storage = "file"
1170-
key = "oauth/kimi-code"
11711153

11721154
[models."kimi-code/kimi-for-coding"]
11731155
provider = "managed:kimi-code"
@@ -1181,3 +1163,20 @@ goal_command = true
11811163
micro_compaction = true
11821164
background_ask = true
11831165
sub_skill = true
1166+
1167+
[thinking]
1168+
mode = "auto"
1169+
1170+
[[permission.rules]]
1171+
decision = "allow"
1172+
pattern = "Read"
1173+
1174+
[[permission.rules]]
1175+
decision = "deny"
1176+
pattern = "Bash(rm -rf*)"
1177+
1178+
[[hooks]]
1179+
event = "PreToolUse"
1180+
matcher = "Bash"
1181+
command = "node ~/.kimi-code/hooks/check-bash.mjs"
1182+
timeout = 5

fix_configs.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import re
2+
import sys
3+
4+
def fix_toml(file_path):
5+
try:
6+
with open(file_path, "r", encoding="utf-8") as f:
7+
content = f.read()
8+
except FileNotFoundError:
9+
print(f"Not found: {file_path}")
10+
return
11+
12+
# 1. Remove hooks = []
13+
content = re.sub(r"^hooks\s*=\s*\[\]\n", "", content, flags=re.MULTILINE)
14+
15+
# 2. Add default_permission_mode = "manual" to top level
16+
if "default_permission_mode" not in content:
17+
content = re.sub(
18+
r"^(default_model\s*=\s*.*)$",
19+
r"\1\ndefault_permission_mode = \"manual\"",
20+
content,
21+
flags=re.MULTILINE
22+
)
23+
24+
# 3. Remove [services.moonshot_search] up to but not including [mcp.client]
25+
# Let's find the boundaries more safely.
26+
# The original file has [services.moonshot_search], [services.moonshot_search.oauth], [services.moonshot_fetch], [services.moonshot_fetch.oauth]
27+
content = re.sub(r"\[services\.moonshot_search\](.*?)(\n\[mcp\.client\])", r"\2", content, flags=re.DOTALL)
28+
29+
# 4. Remove [providers."managed:kimi-code".oauth] block
30+
content = re.sub(r"\[providers\.\"managed:kimi-code\"\.oauth\]\nstorage = \"file\"\nkey = \"oauth/kimi-code\"\n", "", content)
31+
32+
# 5. Add [thinking] mode = "auto"
33+
if "[thinking]" not in content:
34+
content += "\n[thinking]\nmode = \"auto\"\n"
35+
36+
# 6. Add [[permission.rules]] blocks
37+
if "[[permission.rules]]" not in content:
38+
content += """
39+
[[permission.rules]]
40+
decision = "allow"
41+
pattern = "Read"
42+
43+
[[permission.rules]]
44+
decision = "deny"
45+
pattern = "Bash(rm -rf*)"
46+
"""
47+
48+
# 7. Add [[hooks]] block
49+
if "[[hooks]]" not in content:
50+
content += """
51+
[[hooks]]
52+
event = "PreToolUse"
53+
matcher = "Bash"
54+
command = "node ~/.kimi-code/hooks/check-bash.mjs"
55+
timeout = 5
56+
"""
57+
58+
with open(file_path, "w", encoding="utf-8") as f:
59+
f.write(content)
60+
print(f"Fixed {file_path}")
61+
62+
for f in ["config/config.toml", "config/kimi.toml"]:
63+
fix_toml(f)

validator/schemas/config-schema.json

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,54 @@
1414
"default_editor": { "type": "string" },
1515
"theme": { "type": "string", "enum": ["dark", "light", "auto", "gruvbox-dark"] },
1616
"show_thinking_stream": { "type": "boolean" },
17-
"hooks": { "type": "array", "items": { "type": "string" } },
17+
"hooks": {
18+
"type": "array",
19+
"items": {
20+
"anyOf": [
21+
{ "type": "string" },
22+
{
23+
"type": "object",
24+
"properties": {
25+
"event": { "type": "string" },
26+
"matcher": { "type": "string" },
27+
"command": { "type": "string" },
28+
"timeout": { "type": "integer" }
29+
}
30+
}
31+
]
32+
}
33+
},
34+
"default_permission_mode": { "type": "string" },
35+
"thinking": {
36+
"type": "object",
37+
"properties": {
38+
"mode": { "type": "string" }
39+
}
40+
},
41+
"experimental": {
42+
"type": "object",
43+
"properties": {
44+
"micro_compaction": { "type": "boolean" },
45+
"goal_command": { "type": "boolean" },
46+
"background_ask": { "type": "boolean" },
47+
"sub_skill": { "type": "boolean" }
48+
}
49+
},
50+
"permission": {
51+
"type": "object",
52+
"properties": {
53+
"rules": {
54+
"type": "array",
55+
"items": {
56+
"type": "object",
57+
"properties": {
58+
"decision": { "type": "string" },
59+
"pattern": { "type": "string" }
60+
}
61+
}
62+
}
63+
}
64+
},
1865
"merge_all_available_skills": { "type": "boolean" },
1966
"extra_skill_dirs": { "type": "array", "items": { "type": "string" } },
2067
"telemetry": { "type": "boolean" },

validator/schemas/credentials-schema.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@
2121
"minimum": 0,
2222
"description": "Unix timestamp when the token expires"
2323
},
24+
"expires_in": {
25+
"type": ["number", "null"],
26+
"minimum": 0,
27+
"description": "Seconds until the token expires"
28+
},
2429
"refresh_token": {
2530
"type": ["string", "null"],
2631
"description": "OAuth refresh token"

validator/validate_kimi.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,8 +211,11 @@ def validate_config_crossrefs(data: dict[str, Any], base_path: Path) -> list[str
211211
f"(also checked {alt_path})"
212212
)
213213

214-
# 4. hooks paths should exist
214+
# 4. hooks paths should exist (if they are dicts, check the command or script if applicable, but for now we skip or check dict contents)
215215
for hook in data.get("hooks", []):
216+
if isinstance(hook, dict):
217+
# No specific path to validate if it's a dict representing hook config
218+
continue
216219
hook_path = Path(hook)
217220
if not hook_path.is_absolute():
218221
hook_path = base_path.parent / hook_path

0 commit comments

Comments
 (0)