kaiten-cli 0.3.3__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.
- kaiten_cli-0.3.3/.gitignore +29 -0
- kaiten_cli-0.3.3/AGENTS.md +97 -0
- kaiten_cli-0.3.3/API_BEHAVIOR_MATRIX.md +107 -0
- kaiten_cli-0.3.3/ARCHITECTURE.md +183 -0
- kaiten_cli-0.3.3/LIVE_VALIDATION.md +186 -0
- kaiten_cli-0.3.3/PKG-INFO +1110 -0
- kaiten_cli-0.3.3/README.md +1065 -0
- kaiten_cli-0.3.3/SECURITY.md +27 -0
- kaiten_cli-0.3.3/docs/LOCALIZATION_VERIFICATION.md +85 -0
- kaiten_cli-0.3.3/docs/PYPI_PUBLISHING.md +127 -0
- kaiten_cli-0.3.3/docs/RESTRICTIONS_VERIFICATION.md +55 -0
- kaiten_cli-0.3.3/docs/public-api/README.md +89 -0
- kaiten_cli-0.3.3/docs/public-api/automation-tables.json +10777 -0
- kaiten_cli-0.3.3/docs/public-api/contracts.json +39897 -0
- kaiten_cli-0.3.3/docs/public-api/coverage.json +2644 -0
- kaiten_cli-0.3.3/docs/public-api/decisions.json +366 -0
- kaiten_cli-0.3.3/pyproject.toml +102 -0
- kaiten_cli-0.3.3/scripts/audit_public_api.py +555 -0
- kaiten_cli-0.3.3/scripts/benchmark_reference_workflows.py +132 -0
- kaiten_cli-0.3.3/scripts/check_locales.py +190 -0
- kaiten_cli-0.3.3/scripts/check_release.py +149 -0
- kaiten_cli-0.3.3/scripts/extract_automation_docs.cjs +30 -0
- kaiten_cli-0.3.3/scripts/generate_reference_docs.py +418 -0
- kaiten_cli-0.3.3/scripts/normalize_automation_docs.py +148 -0
- kaiten_cli-0.3.3/skills/kaiten-cli-heavy-data/SKILL.md +247 -0
- kaiten_cli-0.3.3/skills/kaiten-cli-metrics/SKILL.md +188 -0
- kaiten_cli-0.3.3/skills/kaiten-cli-mutations/SKILL.md +142 -0
- kaiten_cli-0.3.3/src/kaiten_cli/__init__.py +5 -0
- kaiten_cli-0.3.3/src/kaiten_cli/__main__.py +9 -0
- kaiten_cli-0.3.3/src/kaiten_cli/agent_gateway.py +577 -0
- kaiten_cli-0.3.3/src/kaiten_cli/app.py +1636 -0
- kaiten_cli-0.3.3/src/kaiten_cli/completion.py +570 -0
- kaiten_cli-0.3.3/src/kaiten_cli/discovery.py +39 -0
- kaiten_cli-0.3.3/src/kaiten_cli/errors.py +79 -0
- kaiten_cli-0.3.3/src/kaiten_cli/i18n.py +92 -0
- kaiten_cli-0.3.3/src/kaiten_cli/locales/ru.json +2967 -0
- kaiten_cli-0.3.3/src/kaiten_cli/localized_click.py +160 -0
- kaiten_cli-0.3.3/src/kaiten_cli/models.py +202 -0
- kaiten_cli-0.3.3/src/kaiten_cli/profiles.py +316 -0
- kaiten_cli-0.3.3/src/kaiten_cli/registry/__init__.py +260 -0
- kaiten_cli-0.3.3/src/kaiten_cli/registry/addons.py +392 -0
- kaiten_cli-0.3.3/src/kaiten_cli/registry/audit_and_analytics.py +451 -0
- kaiten_cli-0.3.3/src/kaiten_cli/registry/automation_schema.py +44 -0
- kaiten_cli-0.3.3/src/kaiten_cli/registry/automation_schemas.json +7417 -0
- kaiten_cli-0.3.3/src/kaiten_cli/registry/automations.py +342 -0
- kaiten_cli-0.3.3/src/kaiten_cli/registry/base.py +62 -0
- kaiten_cli-0.3.3/src/kaiten_cli/registry/blockers.py +320 -0
- kaiten_cli-0.3.3/src/kaiten_cli/registry/boards.py +520 -0
- kaiten_cli-0.3.3/src/kaiten_cli/registry/card_relations.py +376 -0
- kaiten_cli-0.3.3/src/kaiten_cli/registry/card_types.py +363 -0
- kaiten_cli-0.3.3/src/kaiten_cli/registry/cards.py +1329 -0
- kaiten_cli-0.3.3/src/kaiten_cli/registry/charts.py +539 -0
- kaiten_cli-0.3.3/src/kaiten_cli/registry/checklists.py +600 -0
- kaiten_cli-0.3.3/src/kaiten_cli/registry/columns.py +558 -0
- kaiten_cli-0.3.3/src/kaiten_cli/registry/comments.py +224 -0
- kaiten_cli-0.3.3/src/kaiten_cli/registry/custom_directories.py +980 -0
- kaiten_cli-0.3.3/src/kaiten_cli/registry/custom_properties.py +1460 -0
- kaiten_cli-0.3.3/src/kaiten_cli/registry/dashboards.py +564 -0
- kaiten_cli-0.3.3/src/kaiten_cli/registry/documents.py +761 -0
- kaiten_cli-0.3.3/src/kaiten_cli/registry/external_links.py +128 -0
- kaiten_cli-0.3.3/src/kaiten_cli/registry/files.py +738 -0
- kaiten_cli-0.3.3/src/kaiten_cli/registry/github_addon.py +613 -0
- kaiten_cli-0.3.3/src/kaiten_cli/registry/iterations.py +397 -0
- kaiten_cli-0.3.3/src/kaiten_cli/registry/lanes.py +205 -0
- kaiten_cli-0.3.3/src/kaiten_cli/registry/live_contracts.py +361 -0
- kaiten_cli-0.3.3/src/kaiten_cli/registry/members.py +336 -0
- kaiten_cli-0.3.3/src/kaiten_cli/registry/module_docs.py +108 -0
- kaiten_cli-0.3.3/src/kaiten_cli/registry/projects.py +369 -0
- kaiten_cli-0.3.3/src/kaiten_cli/registry/query.py +129 -0
- kaiten_cli-0.3.3/src/kaiten_cli/registry/restrictions.py +249 -0
- kaiten_cli-0.3.3/src/kaiten_cli/registry/roles_and_groups.py +1102 -0
- kaiten_cli-0.3.3/src/kaiten_cli/registry/scim.py +263 -0
- kaiten_cli-0.3.3/src/kaiten_cli/registry/service_desk.py +1270 -0
- kaiten_cli-0.3.3/src/kaiten_cli/registry/snapshot.py +187 -0
- kaiten_cli-0.3.3/src/kaiten_cli/registry/spaces.py +272 -0
- kaiten_cli-0.3.3/src/kaiten_cli/registry/subscribers.py +168 -0
- kaiten_cli-0.3.3/src/kaiten_cli/registry/tags.py +193 -0
- kaiten_cli-0.3.3/src/kaiten_cli/registry/time_logs.py +353 -0
- kaiten_cli-0.3.3/src/kaiten_cli/registry/tree.py +352 -0
- kaiten_cli-0.3.3/src/kaiten_cli/registry/utilities.py +287 -0
- kaiten_cli-0.3.3/src/kaiten_cli/registry/webhooks.py +265 -0
- kaiten_cli-0.3.3/src/kaiten_cli/runtime/__init__.py +1 -0
- kaiten_cli-0.3.3/src/kaiten_cli/runtime/automation_validation.py +115 -0
- kaiten_cli-0.3.3/src/kaiten_cli/runtime/behaviors.py +787 -0
- kaiten_cli-0.3.3/src/kaiten_cli/runtime/cache.py +733 -0
- kaiten_cli-0.3.3/src/kaiten_cli/runtime/client.py +387 -0
- kaiten_cli-0.3.3/src/kaiten_cli/runtime/endpoints.py +59 -0
- kaiten_cli-0.3.3/src/kaiten_cli/runtime/executor.py +269 -0
- kaiten_cli-0.3.3/src/kaiten_cli/runtime/fs_security.py +168 -0
- kaiten_cli-0.3.3/src/kaiten_cli/runtime/input.py +310 -0
- kaiten_cli-0.3.3/src/kaiten_cli/runtime/output.py +59 -0
- kaiten_cli-0.3.3/src/kaiten_cli/runtime/public_validation.py +35 -0
- kaiten_cli-0.3.3/src/kaiten_cli/runtime/snapshot_build.py +527 -0
- kaiten_cli-0.3.3/src/kaiten_cli/runtime/snapshot_common.py +363 -0
- kaiten_cli-0.3.3/src/kaiten_cli/runtime/snapshot_query.py +306 -0
- kaiten_cli-0.3.3/src/kaiten_cli/runtime/snapshot_store.py +1192 -0
- kaiten_cli-0.3.3/src/kaiten_cli/runtime/snapshots.py +62 -0
- kaiten_cli-0.3.3/src/kaiten_cli/runtime/sqlite_errors.py +23 -0
- kaiten_cli-0.3.3/src/kaiten_cli/runtime/support/__init__.py +1 -0
- kaiten_cli-0.3.3/src/kaiten_cli/runtime/support/addons.py +953 -0
- kaiten_cli-0.3.3/src/kaiten_cli/runtime/support/audit.py +70 -0
- kaiten_cli-0.3.3/src/kaiten_cli/runtime/support/batch.py +234 -0
- kaiten_cli-0.3.3/src/kaiten_cli/runtime/support/card_move_url.py +213 -0
- kaiten_cli-0.3.3/src/kaiten_cli/runtime/support/cards.py +174 -0
- kaiten_cli-0.3.3/src/kaiten_cli/runtime/support/checklists.py +21 -0
- kaiten_cli-0.3.3/src/kaiten_cli/runtime/support/company_users.py +117 -0
- kaiten_cli-0.3.3/src/kaiten_cli/runtime/support/dashboards.py +35 -0
- kaiten_cli-0.3.3/src/kaiten_cli/runtime/support/documents.py +175 -0
- kaiten_cli-0.3.3/src/kaiten_cli/runtime/support/files.py +561 -0
- kaiten_cli-0.3.3/src/kaiten_cli/runtime/support/markdown_export.py +525 -0
- kaiten_cli-0.3.3/src/kaiten_cli/runtime/support/pagination.py +167 -0
- kaiten_cli-0.3.3/src/kaiten_cli/runtime/support/projects.py +66 -0
- kaiten_cli-0.3.3/src/kaiten_cli/runtime/support/relations.py +86 -0
- kaiten_cli-0.3.3/src/kaiten_cli/runtime/support/restrictions.py +62 -0
- kaiten_cli-0.3.3/src/kaiten_cli/runtime/support/spaces.py +20 -0
- kaiten_cli-0.3.3/src/kaiten_cli/runtime/support/time_logs.py +61 -0
- kaiten_cli-0.3.3/src/kaiten_cli/runtime/support/tree.py +140 -0
- kaiten_cli-0.3.3/src/kaiten_cli/runtime/support/tree_sharing.py +447 -0
- kaiten_cli-0.3.3/src/kaiten_cli/runtime/trace.py +500 -0
- kaiten_cli-0.3.3/src/kaiten_cli/runtime/transforms.py +128 -0
- kaiten_cli-0.3.3/src/kaiten_cli/schema_docs.py +22 -0
- kaiten_cli-0.3.3/src/kaiten_cli/update_check.py +519 -0
- kaiten_cli-0.3.3/tests/conftest.py +35 -0
- kaiten_cli-0.3.3/tests/data/mcp_aliases.txt +423 -0
- kaiten_cli-0.3.3/tests/live/conftest.py +221 -0
- kaiten_cli-0.3.3/tests/live/test_automation_contract.py +102 -0
- kaiten_cli-0.3.3/tests/live/test_restrictions_live.py +21 -0
- kaiten_cli-0.3.3/tests/live/test_sandbox_live_full.py +1757 -0
- kaiten_cli-0.3.3/tests/test_addons_and_github_addon.py +1613 -0
- kaiten_cli-0.3.3/tests/test_agent_gateway.py +487 -0
- kaiten_cli-0.3.3/tests/test_audit_and_analytics.py +198 -0
- kaiten_cli-0.3.3/tests/test_automation_schemas.py +195 -0
- kaiten_cli-0.3.3/tests/test_card_types_and_custom_properties.py +166 -0
- kaiten_cli-0.3.3/tests/test_cards_move_by_url.py +284 -0
- kaiten_cli-0.3.3/tests/test_charts.py +184 -0
- kaiten_cli-0.3.3/tests/test_cli_smoke.py +373 -0
- kaiten_cli-0.3.3/tests/test_column_settings.py +119 -0
- kaiten_cli-0.3.3/tests/test_command_resolution.py +14 -0
- kaiten_cli-0.3.3/tests/test_completion_tail.py +265 -0
- kaiten_cli-0.3.3/tests/test_dashboards.py +389 -0
- kaiten_cli-0.3.3/tests/test_developer_parity_gaps.py +284 -0
- kaiten_cli-0.3.3/tests/test_discovery.py +168 -0
- kaiten_cli-0.3.3/tests/test_docs_structure.py +59 -0
- kaiten_cli-0.3.3/tests/test_documents_and_tree.py +622 -0
- kaiten_cli-0.3.3/tests/test_domain_expansion.py +549 -0
- kaiten_cli-0.3.3/tests/test_entrypoints.py +57 -0
- kaiten_cli-0.3.3/tests/test_executor_architecture.py +12 -0
- kaiten_cli-0.3.3/tests/test_executor_http.py +575 -0
- kaiten_cli-0.3.3/tests/test_file_downloads.py +249 -0
- kaiten_cli-0.3.3/tests/test_file_uploads.py +130 -0
- kaiten_cli-0.3.3/tests/test_fs_security.py +58 -0
- kaiten_cli-0.3.3/tests/test_generated_docs.py +16 -0
- kaiten_cli-0.3.3/tests/test_input_parsing.py +227 -0
- kaiten_cli-0.3.3/tests/test_investigation_workflows.py +545 -0
- kaiten_cli-0.3.3/tests/test_iterations.py +299 -0
- kaiten_cli-0.3.3/tests/test_live_contracts.py +51 -0
- kaiten_cli-0.3.3/tests/test_local_snapshots.py +804 -0
- kaiten_cli-0.3.3/tests/test_localization.py +358 -0
- kaiten_cli-0.3.3/tests/test_markdown_export.py +230 -0
- kaiten_cli-0.3.3/tests/test_narrow_list_fields.py +23 -0
- kaiten_cli-0.3.3/tests/test_output_human.py +15 -0
- kaiten_cli-0.3.3/tests/test_output_json.py +61 -0
- kaiten_cli-0.3.3/tests/test_pagination.py +154 -0
- kaiten_cli-0.3.3/tests/test_private_files.py +327 -0
- kaiten_cli-0.3.3/tests/test_profiles.py +468 -0
- kaiten_cli-0.3.3/tests/test_public_api_cutover.py +128 -0
- kaiten_cli-0.3.3/tests/test_public_contract_parity.py +380 -0
- kaiten_cli-0.3.3/tests/test_public_input_transport.py +310 -0
- kaiten_cli-0.3.3/tests/test_rate_limit_policy.py +221 -0
- kaiten_cli-0.3.3/tests/test_registry_examples.py +49 -0
- kaiten_cli-0.3.3/tests/test_release.py +232 -0
- kaiten_cli-0.3.3/tests/test_restrictions.py +328 -0
- kaiten_cli-0.3.3/tests/test_roles_groups_and_subscribers.py +303 -0
- kaiten_cli-0.3.3/tests/test_runtime_cache.py +623 -0
- kaiten_cli-0.3.3/tests/test_service_desk.py +155 -0
- kaiten_cli-0.3.3/tests/test_shell_completion.py +431 -0
- kaiten_cli-0.3.3/tests/test_skills_structure.py +98 -0
- kaiten_cli-0.3.3/tests/test_timeout_policy.py +24 -0
- kaiten_cli-0.3.3/tests/test_transforms.py +26 -0
- kaiten_cli-0.3.3/tests/test_tree_entity_sharing.py +444 -0
- kaiten_cli-0.3.3/tests/test_update_check.py +532 -0
- kaiten_cli-0.3.3/tests/test_utilities_remainder.py +75 -0
- kaiten_cli-0.3.3/tests/test_webhooks_and_automations.py +129 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
.venv/
|
|
2
|
+
.verify-venv/
|
|
3
|
+
__pycache__/
|
|
4
|
+
.pytest_cache/
|
|
5
|
+
.coverage
|
|
6
|
+
.coverage.*
|
|
7
|
+
coverage.xml
|
|
8
|
+
htmlcov/
|
|
9
|
+
.mypy_cache/
|
|
10
|
+
.ruff_cache/
|
|
11
|
+
.claude-flow/
|
|
12
|
+
.bin/
|
|
13
|
+
.pipx/
|
|
14
|
+
.uv-tools/
|
|
15
|
+
build/
|
|
16
|
+
dist/
|
|
17
|
+
*.egg-info/
|
|
18
|
+
*.pyc
|
|
19
|
+
.env
|
|
20
|
+
.env_stage
|
|
21
|
+
.env_private
|
|
22
|
+
.DS_Store
|
|
23
|
+
/ARCHITECTURE_REVIEW.md
|
|
24
|
+
/docs/archive/
|
|
25
|
+
/docs/audits/
|
|
26
|
+
/scripts/analyze_codex_kaiten_sessions.py
|
|
27
|
+
/tests/test_analyze_codex_kaiten_sessions.py
|
|
28
|
+
/PLAN*.md
|
|
29
|
+
/PARITY_CHECKLIST.md
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# kaiten-cli for Agents
|
|
2
|
+
|
|
3
|
+
This file only captures agent-specific guidance.
|
|
4
|
+
|
|
5
|
+
For install, human-oriented usage, and the full docs map, start with [README.md](README.md).
|
|
6
|
+
For the full command catalog, use [COMMAND_REFERENCE.md](COMMAND_REFERENCE.md).
|
|
7
|
+
For the system map, use [ARCHITECTURE.md](ARCHITECTURE.md).
|
|
8
|
+
For optimized LLM workflows, start with:
|
|
9
|
+
|
|
10
|
+
- [skills/kaiten-cli-heavy-data/SKILL.md](skills/kaiten-cli-heavy-data/SKILL.md)
|
|
11
|
+
- [skills/kaiten-cli-metrics/SKILL.md](skills/kaiten-cli-metrics/SKILL.md)
|
|
12
|
+
- [skills/kaiten-cli-mutations/SKILL.md](skills/kaiten-cli-mutations/SKILL.md)
|
|
13
|
+
|
|
14
|
+
## Conversation locale
|
|
15
|
+
|
|
16
|
+
Pass `--locale ru` for Russian conversations and `--locale en` for English or
|
|
17
|
+
other languages, before the command name in every invocation, including help,
|
|
18
|
+
discovery and `--json`. Change it when the user changes the conversation language.
|
|
19
|
+
Explicit `--locale` overrides `KAITEN_CLI_LOCALE`; the default is `en`.
|
|
20
|
+
The CLI does not infer conversation language from the operating system.
|
|
21
|
+
Only CLI-owned prose is localized; command names, JSON keys, enum values and
|
|
22
|
+
Kaiten/user data remain unchanged. Examples below omit the locale for brevity;
|
|
23
|
+
add the current conversation locale when executing them.
|
|
24
|
+
|
|
25
|
+
## Discovery-first flow
|
|
26
|
+
|
|
27
|
+
Prefer this sequence before calling mutations or heavy commands:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
kaiten --help
|
|
31
|
+
kaiten search-tools cards
|
|
32
|
+
kaiten describe cards.list
|
|
33
|
+
kaiten examples cards.list
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Run discovery once per unfamiliar command family, mutation workflow, or heavy
|
|
37
|
+
read. Reuse the discovered contract inside the same workflow instead of
|
|
38
|
+
repeating `describe` before every call.
|
|
39
|
+
|
|
40
|
+
Use `--json` by default for machine-safe parsing:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
kaiten --json spaces list --compact --fields id,title
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
If the workflow will ask many questions about the same space or board set, switch early to the local-first path:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
kaiten --json snapshot build --name team-basic --space-id 10 --preset basic
|
|
50
|
+
kaiten --json query cards --snapshot team-basic --view summary --fields id,title,state
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Config and precedence
|
|
54
|
+
|
|
55
|
+
Credential resolution order:
|
|
56
|
+
|
|
57
|
+
1. `--profile <name>`
|
|
58
|
+
2. active profile from config
|
|
59
|
+
3. `KAITEN_DOMAIN` + `KAITEN_TOKEN`
|
|
60
|
+
|
|
61
|
+
Recommended persistent setup:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
kaiten profile add main --domain <company-subdomain-or-url> --token <api-token> --set-active
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Safety and efficiency
|
|
68
|
+
|
|
69
|
+
- Start with read-only commands.
|
|
70
|
+
- Normal profiles can mutate; treat real credentials as real writes.
|
|
71
|
+
- For analysis-only workflows, use global `--read-only` or `KAITEN_CLI_READ_ONLY=1`; this blocks remote mutations while allowing local snapshot lifecycle operations and the POST-backed chart retrieval commands reported with `read_only_allowed=true`.
|
|
72
|
+
- `KAITEN_LIVE=1|true` is the explicit per-run gate for the live test suite.
|
|
73
|
+
- Prefer `--compact` and `--fields` to reduce payload and token cost.
|
|
74
|
+
- Request-scoped cache for safe GETs is built in; default `--cache-mode auto` also persists cacheable safe reads across CLI processes.
|
|
75
|
+
- Omit `--cache-mode` for ordinary workflows: this keeps the default `auto`.
|
|
76
|
+
- Use `--cache-mode refresh` once at a freshness boundary; never put it inside an entity loop. For a reused local working set, prefer `snapshot refresh`.
|
|
77
|
+
- Use `--cache-mode off` only for cache debugging, privacy-sensitive reads, or high-churn polling.
|
|
78
|
+
- Use `--cache-mode readwrite` only with an explicit, meaningful `--cache-ttl-seconds` when a fixed TTL is required.
|
|
79
|
+
- Heavy/batch reads and dense repeated entity reads get longer adaptive TTLs in `auto`; do not force tiny TTLs in wrapper scripts unless freshness is the main requirement.
|
|
80
|
+
- JSON responses include top-level `stats`; check `http_request_count`, `api_wait_ms`, cache counters, and grouped path families before repeating expensive calls.
|
|
81
|
+
- Use `--verbose` when you need request-path and execution diagnostics; diagnostics stay in `stderr`.
|
|
82
|
+
- Use `--trace-file` or `KAITEN_TRACE_FILE` when you need a JSONL trace of real command cost across a longer workflow.
|
|
83
|
+
- Trace is required for wrappers with at least three CLI commands, expected runs above ten HTTP requests, or unavoidable loops. Review it with `kaiten --json trace summarize --file <trace.jsonl>`.
|
|
84
|
+
- Treat `aggregated` and `synthetic` tools as potentially more expensive than `direct_http`.
|
|
85
|
+
- For high-cardinality reads, follow the heavy-data skill instead of inventing a per-entity loop.
|
|
86
|
+
- For metrics workflows, follow the metrics skill instead of reconstructing raw history one card at a time.
|
|
87
|
+
- For repeated report or analytics questions on one working set, prefer `snapshot build` plus `query cards` / `query metrics` over re-fetching the same population.
|
|
88
|
+
- Keep `query cards` in `summary` view by default; use `detail` or `evidence` only after local candidate reduction.
|
|
89
|
+
- Treat `query metrics` as a generic local metrics layer unless a workflow explicitly defines tenant-specific flow semantics outside the CLI.
|
|
90
|
+
- Prefer `space-topology.get`, `cards.batch-get`, `time-logs.batch-list`, `space-activity-all.get`, `card-children.batch-list`, `comments.batch-list`, and `card-location-history.batch-get` over manual orchestration loops.
|
|
91
|
+
- When two or more entity IDs are known and `describe` reports `bulk_alternative`, use the bulk command.
|
|
92
|
+
- When the same population is needed a second time, build a snapshot and continue with local `query cards` / `query metrics`.
|
|
93
|
+
- Before a live mutation, use `kaiten --json --profile <name> --read-only profile probe`, then follow the mutation skill: discovery, read-only investigation, exact preview, authorization, resumable manifest, small batches, and field-scoped readback.
|
|
94
|
+
- Addon state lives outside the normal card fields: use `card-addon-data` / `user-addon-data` for raw addon storage, and the `github-addon` commands for PRs, branches, commits and issues shown on a card.
|
|
95
|
+
- Attaching a PR to a card usually means the GitHub addon, not `external-links create`; check both sources when looking for every PR a card references.
|
|
96
|
+
- The GitHub addon UUID is derived from its mount path only on on-premises Kaiten; elsewhere it is random. `addons uid` returns the derived guess, `space-addons list` and `company-addons list` return the real one, and the `github-addon` commands re-resolve it from the card's space when the guess finds no data.
|
|
97
|
+
- Live validation is opt-in and documented in [LIVE_VALIDATION.md](LIVE_VALIDATION.md).
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# API Behavior Matrix
|
|
2
|
+
|
|
3
|
+
Этот документ фиксирует API-контракты для `kaiten-cli`, ранее наблюдавшиеся на live test tenant и закодированные в текущем live harness.
|
|
4
|
+
|
|
5
|
+
Запуск live suite по-прежнему gated только через `KAITEN_LIVE=1|true`; special-case по домену или profile metadata для этого не используется.
|
|
6
|
+
|
|
7
|
+
## Verification metadata
|
|
8
|
+
|
|
9
|
+
| Поле | Значение |
|
|
10
|
+
|------|----------|
|
|
11
|
+
| Contract baseline | `kaiten-cli v0.1.23` |
|
|
12
|
+
| Tenant class | Kaiten sandbox test tenant |
|
|
13
|
+
| Текущий аудит | `2026-07-09`; live suite **не запускался** |
|
|
14
|
+
| Последняя полная live campaign | `TBD`: дата и commit не подтверждены в репозитории |
|
|
15
|
+
| Источник до следующего live run | checked-in contracts и `tests/live/`; записи ниже нельзя считать повторно подтверждёнными текущим аудитом |
|
|
16
|
+
|
|
17
|
+
После следующей полной live campaign эту таблицу нужно обновить точными датой, commit SHA, версией CLI и tenant class. Secrets, tenant URL и идентификаторы тестовых сущностей сюда не записываются.
|
|
18
|
+
|
|
19
|
+
## Default rule
|
|
20
|
+
|
|
21
|
+
Все canonical команды из registry, которые не перечислены ниже, считаются `live_passed`: они должны проходить по normal success-path в полном live suite.
|
|
22
|
+
|
|
23
|
+
## Validated success-path contracts with special notes
|
|
24
|
+
|
|
25
|
+
| Command | Verb / Path | Status | Notes |
|
|
26
|
+
|---------|-------------|--------|-------|
|
|
27
|
+
| `automations.create` | `POST /spaces/{space_id}/automations` | `live_passed` | Успешно проходит на sandbox с known-good payload: `trigger.type=card_created`, `action.type=add_assignee`, `created`, `data.variant`, `data.userId`. |
|
|
28
|
+
| `automations.update` | `PATCH /spaces/{space_id}/automations/{automation_id}` | `live_passed` | Успешно проходит для automation, созданной с known-good payload. |
|
|
29
|
+
| `automations.delete` | `DELETE /spaces/{space_id}/automations/{automation_id}` | `live_passed` | Успешный cleanup подтверждён в live validation. |
|
|
30
|
+
|
|
31
|
+
## Runtime-shaped contracts
|
|
32
|
+
|
|
33
|
+
| Command | Verb / Path | Status | Notes |
|
|
34
|
+
|---------|-------------|--------|-------|
|
|
35
|
+
| `boards.delete` | `DELETE /spaces/{space_id}/boards/{board_id}` | `live_passed_with_runtime_fix` | Sandbox требует `force`; CLI передаёт его в query и body. |
|
|
36
|
+
|
|
37
|
+
## Synthetic reads
|
|
38
|
+
|
|
39
|
+
| Command | Primary endpoint | Status | Fallback |
|
|
40
|
+
|---------|------------------|--------|----------|
|
|
41
|
+
| `projects.cards.list` | `GET /projects/{project_id}/cards` | `synthetic_read` | При `405` CLI делает `GET /projects/{project_id}?with_cards_data=true` и извлекает embedded cards list. |
|
|
42
|
+
| `checklists.list` | `GET /cards/{card_id}` | `synthetic_read` | Extracts embedded `checklists` instead of the collection GET, which returned 405 on the tested tenant and was also reported on production in [kaiten-mcp PR #4](https://github.com/ViktorOgnev/kaiten-mcp/pull/4). |
|
|
43
|
+
| `checklist-items.list` | `GET /cards/{card_id}/checklists/{checklist_id}` | `synthetic_read` | Extracts `items` from the individual checklist, avoiding the unsupported collection GET. API errors are preserved. |
|
|
44
|
+
|
|
45
|
+
## Stable expected-error contracts
|
|
46
|
+
|
|
47
|
+
| Command | Verb / Path | Status | Expected statuses | Notes |
|
|
48
|
+
|---------|-------------|--------|-------------------|-------|
|
|
49
|
+
| `removed-boards.list` | `GET /boards/removed` | `live_passed_as_expected_error` | `405` | Sandbox recycle-bin endpoint unsupported. |
|
|
50
|
+
| `removed-cards.list` | `GET /cards/removed` | `live_passed_as_expected_error` | `405` | Sandbox recycle-bin endpoint unsupported. |
|
|
51
|
+
| `card-subscribers.list` | `GET /cards/{card_id}/subscribers` | `live_passed_as_expected_error` | `405` | Direct subscriber listing unsupported on sandbox. |
|
|
52
|
+
| `column-subscribers.list` | `GET /columns/{column_id}/subscribers` | `live_passed_as_expected_error` | `405` | Direct subscriber listing unsupported on sandbox. |
|
|
53
|
+
| `service-desk.users.update` | `PATCH /service-desk/users/{user_id}` | `live_passed_as_expected_error` | `400`, `403`, `404`, `405` | Для текущего sandbox-аккаунта API возвращает `400 Should be service desk user`, если пользователь не является SD user. |
|
|
54
|
+
| `service-desk.organization-users.update` | `PATCH /service-desk/organizations/{organization_id}/users/{user_id}` | `live_passed_as_expected_error` | `400`, `403`, `404`, `405` | Обновление permissions для organization-user остаётся sandbox-dependent even after successful add. |
|
|
55
|
+
|
|
56
|
+
## Conditional success-or-error contracts
|
|
57
|
+
|
|
58
|
+
Эти команды остаются live-correct, даже если sandbox вместо success-path возвращает ожидаемый `4xx`.
|
|
59
|
+
|
|
60
|
+
| Command family | Status | Expected statuses | Notes |
|
|
61
|
+
|----------------|--------|-------------------|-------|
|
|
62
|
+
| `sprints.create` | `live_passed_as_expected_error` | `403`, `405` | Создание спринта зависит от sandbox permissions/capabilities. |
|
|
63
|
+
| `sprints.list` | `live_passed_as_expected_error` | `403`, `405` | Чтение списка спринтов зависит от sandbox permissions/capabilities. |
|
|
64
|
+
| `service-desk.users.set-temp-password` | `live_passed_as_expected_error` | `403`, `404`, `405` | На sandbox может либо успешно сработать, либо вернуть documented `403/404/405`; live suite принимает оба исхода. |
|
|
65
|
+
| `sprints.get`, `sprints.delete` | `live_passed_as_expected_error` | `403`, `404`, `405` | При недоступном create live suite валидирует sentinel error contract. |
|
|
66
|
+
| `sprints.update` | `live_passed_as_expected_error` | `403`, `404`, `405`, `500` | На sandbox update по sentinel sprint id может отдавать `500`; это зафиксировано как documented sandbox defect contract. |
|
|
67
|
+
| `automations.get` | `live_passed_as_expected_error` | `405` | GET-single для automation может быть unsupported даже после успешного create. |
|
|
68
|
+
| `automations.copy` | `live_passed_as_expected_error` | `400`, `403`, `404`, `405` | Даже при live-valid source automation copy остаётся sandbox-dependent. |
|
|
69
|
+
| `webhooks.get`, `webhooks.delete` | `live_passed_as_expected_error` | `404`, `405` | После create эти endpoints могут быть недоступны как отдельные singleton operations. |
|
|
70
|
+
| `workflows.create` | `live_passed_as_expected_error` | `403`, `405` | Создание workflow зависит от sandbox permissions/capabilities. |
|
|
71
|
+
| `workflows.get`, `workflows.update`, `workflows.delete` | `live_passed_as_expected_error` | `403`, `404`, `405` | При недоступном create live suite валидирует sentinel error contract. |
|
|
72
|
+
| `service-desk.requests.create` | `live_passed_as_expected_error` | `400`, `403`, `404`, `405` | Request creation permission-dependent. |
|
|
73
|
+
| `service-desk.requests.get`, `service-desk.requests.update`, `service-desk.requests.delete` | `live_passed_as_expected_error` | `403`, `404`, `405` | При недоступном create live suite валидирует sentinel error contract. |
|
|
74
|
+
| `service-desk.sla-rules.create` | `live_passed_as_expected_error` | `400`, `403`, `404`, `405` | SLA rule creation schema- and permission-dependent. |
|
|
75
|
+
| `service-desk.sla-rules.update`, `service-desk.sla-rules.delete` | `live_passed_as_expected_error` | `400`, `403`, `404`, `405` | При недоступном create live suite валидирует sentinel error contract. |
|
|
76
|
+
| `compute-jobs.cancel` | `live_passed_as_expected_error` | `400`, `404`, `409` | Cancel зависит от состояния compute job. |
|
|
77
|
+
| `user-timers.list` | `live_passed_as_expected_error` | `403`, `405` | Sandbox timer surface нестабилен. |
|
|
78
|
+
| `user-timers.create` | `live_passed_as_expected_error` | `400`, `403`, `405`, `409` | Timer creation зависит от sandbox semantics. |
|
|
79
|
+
| `user-timers.get`, `user-timers.update`, `user-timers.delete` | `live_passed_as_expected_error` | `403`, `404`, `405` | При недоступном create live suite валидирует sentinel error contract. |
|
|
80
|
+
|
|
81
|
+
## Not yet live-validated
|
|
82
|
+
|
|
83
|
+
Эти команды добавлены после последней полной live campaign. Сценарии для них уже есть в
|
|
84
|
+
`tests/live/`, но прогона, подтверждающего контракт, не было, поэтому default rule
|
|
85
|
+
`live_passed` на них не распространяется.
|
|
86
|
+
|
|
87
|
+
| Command family | Verb / Path | Status | Notes |
|
|
88
|
+
|----------------|-------------|--------|-------|
|
|
89
|
+
| `restrictions.list`, `restrictions.get` | `GET /spaces/{space_id}/restrictions` | `live_not_validated` | Недокументированное расширение по серверному коду. Весь список без пагинации; `get` выбирает UUID из списка и возвращает явную ошибку при отсутствии. Ограничения workflow исключены. |
|
|
90
|
+
| `restrictions.create`, `restrictions.copy` | `POST /spaces/{space_id}/restrictions` | `live_not_validated` | Создание принимает `conditions` и `restrictions`; копирование передаёт `source_restriction_id` в целевое пространство и сохраняет фактический статус ответа, включая `broken`. |
|
|
91
|
+
| `restrictions.update`, `restrictions.delete` | `PATCH` / `DELETE /spaces/{space_id}/restrictions/{restriction_id}` | `live_not_validated` | PATCH передаёт только заданные поля; массивы заменяются целиком. `status=active\|disabled`. Для `error_text` необходимо ещё одно поле. DELETE может вернуть пустое тело. Opt-in lifecycle и проверяемая очистка добавлены, но не запускались. |
|
|
92
|
+
| `addons.list` | `GET /addons` | `live_not_validated` | Каталог опубликованных аддонов без фильтра по компании; live suite принимает success или `403/405`. |
|
|
93
|
+
| `company-addons.list` | `GET /company/addons` | `live_not_validated` | Аддоны, зарегистрированные самой компанией, включая неопубликованные. |
|
|
94
|
+
| `addons.uid` | локальная команда | `live_not_validated` | UUID v5 считается локально, обращения к API нет; проверяется совпадение с эталонным UID `/github`. |
|
|
95
|
+
| `space-addons.list` | `GET /spaces/{space_id}/addons` | `live_not_validated` | Требует права `space.addons.read`. |
|
|
96
|
+
| `space-addons.install`, `space-addons.uninstall` | `PATCH` / `DELETE /spaces/{space_id}/addons/{addon_uid}` | `live_not_validated` | В live suite проверяются только на sentinel UID, чтобы не менять набор аддонов реального пространства. Sentinel подобран так, чтобы проходить `uuidIdRule`, иначе probe подтверждал бы 404 от несовпадения маршрута, а не контракт эндпоинта. |
|
|
97
|
+
| `card-addon-data.get`, `user-addon-data.get` | `GET .../addons-data/{addon_uid}` | `live_not_validated` | Чтение; для неустановленного аддона возможен пустой ответ или `403/404/405`. |
|
|
98
|
+
| `card-addon-data.set`, `user-addon-data.set` | `PATCH .../addons-data/{addon_uid}` | `live_not_validated` | Запись проверяется только на sentinel UID: реальная запись требует установленного аддона и `card.update`. |
|
|
99
|
+
| `github-addon.*.list` | `GET /cards/{card_id}/addons-data/{addon_uid}` | `live_not_validated` | Чтение shared-ключей `attachedPulls`, `attachedBranches`, `attachedCommits`, `attachedIssues`. При пустом ответе на выведенный UID дополнительно читаются `GET /cards/{id}` и `GET /spaces/{id}/addons`, чтобы взять реально зарегистрированный UID. |
|
|
100
|
+
| `github-addon.*.attach`, `github-addon.*.detach` | `PATCH /cards/{card_id}/addons-data/{addon_uid}` | `live_not_validated` | Live suite покрывает только `--dry-run`: реальная запись изменила бы данные аддона на живой карточке. |
|
|
101
|
+
|
|
102
|
+
## Policy exclusions
|
|
103
|
+
|
|
104
|
+
| Command | Status | Notes |
|
|
105
|
+
|---------|--------|-------|
|
|
106
|
+
| `api-keys.create` | `policy_excluded` | Создание ключей не тестируется live, потому что clean teardown потребовал бы testing delete. |
|
|
107
|
+
| `api-keys.delete` | `policy_excluded` | Явно исключено по пользовательской политике. |
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# Architecture
|
|
2
|
+
|
|
3
|
+
`kaiten-cli` is organized around one core idea: the tool surface is declared once, in the registry, and every other layer consumes that metadata.
|
|
4
|
+
|
|
5
|
+
## System Map
|
|
6
|
+
|
|
7
|
+
Runtime flow:
|
|
8
|
+
|
|
9
|
+
`registry -> discovery/app -> input merge -> executor -> client -> transforms/output`
|
|
10
|
+
|
|
11
|
+
For high-cardinality reads there is one more path:
|
|
12
|
+
|
|
13
|
+
`registry -> discovery/app -> input merge -> executor -> execution context -> runtime behavior -> bulk worker pool -> per-worker clients`
|
|
14
|
+
|
|
15
|
+
For repeated report and analytics workflows there is also a local-first path:
|
|
16
|
+
|
|
17
|
+
`registry -> discovery/app -> input merge -> executor -> local snapshot store -> local query/metrics`
|
|
18
|
+
|
|
19
|
+
Successful interactive commands have an independent post-command path:
|
|
20
|
+
|
|
21
|
+
`app -> install metadata -> cached Git tag check -> optional installer confirmation`
|
|
22
|
+
|
|
23
|
+
Main layers:
|
|
24
|
+
|
|
25
|
+
- `src/kaiten_cli/registry/`
|
|
26
|
+
Source of truth for the command catalog. Each tool is declared as a `ToolSpec` with canonical name, MCP alias, schema, examples, request metadata, response policy, and optional runtime behavior.
|
|
27
|
+
- `src/kaiten_cli/runtime/`
|
|
28
|
+
Execution layer. Builds requests, resolves profiles and cache settings, applies read-only mutation policies, runs HTTP calls, handles synthetic and aggregated reads, persists local snapshots, and serves local-only query commands.
|
|
29
|
+
- `src/kaiten_cli/runtime/support/`
|
|
30
|
+
Domain-specific helpers used by runtime behaviors for documents, projects, tree aggregation, cards bulk pagination, relation/comment batch reads, activity pagination, and space topology aggregation.
|
|
31
|
+
- top-level `src/kaiten_cli/`
|
|
32
|
+
Stable package surface and shared core: `app.py`, `discovery.py`, `profiles.py`, `models.py`, `errors.py`, entrypoints.
|
|
33
|
+
|
|
34
|
+
## Registry vs Runtime
|
|
35
|
+
|
|
36
|
+
This repo does not have two different sets of tools.
|
|
37
|
+
|
|
38
|
+
- `registry` defines the tools.
|
|
39
|
+
- `runtime` executes the tools.
|
|
40
|
+
|
|
41
|
+
If a command looks “special”, it is still a registry-defined tool. The only difference is that its `ToolSpec.runtime_behavior` points to a request shaper or custom executor in `src/kaiten_cli/runtime/behaviors.py`.
|
|
42
|
+
|
|
43
|
+
That means:
|
|
44
|
+
|
|
45
|
+
- `cards.list` is a registry tool with direct HTTP execution
|
|
46
|
+
- `projects.cards.list` is a registry tool with synthetic execution
|
|
47
|
+
- `cards.list-all` is a registry tool with aggregated execution
|
|
48
|
+
|
|
49
|
+
The command catalog stays centralized even when runtime semantics differ.
|
|
50
|
+
|
|
51
|
+
## Output Locale
|
|
52
|
+
|
|
53
|
+
`i18n.py` holds an invocation-scoped `ContextVar`. The root Click group and public
|
|
54
|
+
entrypoint resolve `--locale ru|en` before help and parser errors; the flag wins
|
|
55
|
+
over `KAITEN_CLI_LOCALE`, then `en`. OS locale and profiles do not participate.
|
|
56
|
+
The caller (agent) chooses the language from the conversation.
|
|
57
|
+
|
|
58
|
+
English source templates are stable message IDs. `locales/ru.json` is an offline
|
|
59
|
+
catalog shipped in the wheel. Runtime prose opts in with `tr`; discovery copies
|
|
60
|
+
only explicitly defined prose fields, including JSON Schema descriptions.
|
|
61
|
+
API payloads, user values, enum values, command identifiers and trace fields are
|
|
62
|
+
never passed through recursive translation. Raw API/OS/library diagnostics retain
|
|
63
|
+
their source language inside a localized CLI message.
|
|
64
|
+
|
|
65
|
+
`localized_click.py` binds Click's module-local gettext callbacks once to the
|
|
66
|
+
context-aware dispatcher. Help is rendered from command copies; Click's cached
|
|
67
|
+
help option remains English. Context tokens reset on success and failure, and
|
|
68
|
+
async workers inherit the invocation locale. Dependency updates must pass the
|
|
69
|
+
catalog check and sequential/concurrent locale regression tests.
|
|
70
|
+
|
|
71
|
+
Registry metadata stays canonical English for stable generated documentation.
|
|
72
|
+
Search uses both language descriptions plus private `search_terms`; changing the
|
|
73
|
+
output locale cannot change ranking. Agent instructions and gateway prompts
|
|
74
|
+
require an explicit locale per invocation. This is a language contract, not a
|
|
75
|
+
claim of improved model accuracy; that requires separate evaluation.
|
|
76
|
+
|
|
77
|
+
Run `python scripts/check_locales.py` for coverage, formatting placeholders and
|
|
78
|
+
command-flag preservation. Unknown messages fall back to English at runtime;
|
|
79
|
+
the check and tests fail for missing known translations. See
|
|
80
|
+
[localization verification](docs/LOCALIZATION_VERIFICATION.md) for invariants and evidence.
|
|
81
|
+
|
|
82
|
+
## Execution Context and Cache
|
|
83
|
+
|
|
84
|
+
Each CLI invocation builds one execution context for the selected profile.
|
|
85
|
+
|
|
86
|
+
- request-scoped cache is always enabled for safe GET reads
|
|
87
|
+
- identical in-flight GETs are deduplicated inside the same execution context
|
|
88
|
+
- persistent disk cache defaults to `--cache-mode auto` for cacheable safe reads
|
|
89
|
+
- persistent cache scope includes a one-way credential fingerprint, so different users of the same tenant/profile cannot reuse each other's cached responses
|
|
90
|
+
- `auto` uses adaptive TTLs: small fresh reads stay short, while heavy batch/aggregated reads, closed historical windows, and dense same-family entity loops are retained longer
|
|
91
|
+
- worker clients share one execution-scoped rate limiter instead of multiplying the request budget by worker count
|
|
92
|
+
- every attempted remote mutation clears persistent cache for the current credential scope, including ambiguous failures, so verification reads cannot reuse pre-mutation data
|
|
93
|
+
- incompatible or corrupt local sqlite cache files are treated as disposable state and recreated automatically
|
|
94
|
+
- credential config, HTTP cache, snapshots, and trace files are stored with user-only file permissions (`0600`); application-owned parent directories are `0700`, while existing user-selected trace/config parent modes are preserved
|
|
95
|
+
- JSON success/error envelopes include runtime `stats` with duration, HTTP/API wait, cache counters, and grouped method/path-family aggregates
|
|
96
|
+
- optional JSONL trace output can be appended through `--trace-file` or `KAITEN_TRACE_FILE`
|
|
97
|
+
|
|
98
|
+
This keeps freshness controls explicit (`refresh` / `off`) while reducing repeated entity, page, and card-scoped reads in synthetic, aggregated, worker-pooled, and external-script paths.
|
|
99
|
+
|
|
100
|
+
## Post-command Update Check
|
|
101
|
+
|
|
102
|
+
`update_check.py` is outside the Kaiten execution/runtime path. It recognizes only
|
|
103
|
+
remote Git installations described by standard Python `direct_url.json` metadata,
|
|
104
|
+
detects the owning `pipx`, `uv tool`, or pip environment, and compares the
|
|
105
|
+
installed version with stable `vX.Y.Z` tags from the same remote.
|
|
106
|
+
|
|
107
|
+
The check runs only after a successful interactive command, is cached for 24
|
|
108
|
+
hours, and is disabled for JSON/non-TTY/help/version/completion calls. Network and
|
|
109
|
+
metadata failures are fail-open. The cache stores a source hash rather than the
|
|
110
|
+
Git URL, and installer commands are passed directly to `subprocess` without a
|
|
111
|
+
shell. A confirmed update is a separate local side effect and does not alter the
|
|
112
|
+
already completed Kaiten command.
|
|
113
|
+
|
|
114
|
+
## Mutation Safety
|
|
115
|
+
|
|
116
|
+
- Transport retries are limited to safe HTTP methods. An ambiguous timeout, connection failure, HTTP 5xx, or malformed successful response for a remote mutation is returned without retry and explicitly tells the caller to verify remote state.
|
|
117
|
+
- Global `--read-only` and `KAITEN_CLI_READ_ONLY=1` block registry tools that mutate Kaiten through `RuntimeBehavior.enforce_mutation_guard`.
|
|
118
|
+
- Local snapshot lifecycle commands opt out of that guard because they only write derived local sqlite state; their Kaiten API calls remain reads.
|
|
119
|
+
- Three POST-backed chart retrieval commands opt out because they only submit analytics filters; chart build commands remain guarded because they create transient compute jobs.
|
|
120
|
+
- Discovery exposes `read_only_allowed` separately from HTTP-method-derived `mutation`.
|
|
121
|
+
- The agent gateway passes remote and local-storage read-only environment policies, disables ambient Codex user config/rules, applies request limits, and requires bearer authentication for non-loopback binds. Existing snapshots use a SQLite read-only connection inside that sandbox; snapshot lifecycle writes are rejected. Because the child still has shell access and Kaiten credentials, this is a cooperative safety layer rather than a hard authorization boundary; untrusted/non-loopback deployments require server-side credential restrictions and an external TLS/connection-limiting proxy.
|
|
122
|
+
|
|
123
|
+
The trace layer records command-level facts such as duration, real HTTP request count, API wait time, retry/cache counters, grouped path families, and bulk metadata. It exists because outer Codex/session logs do not reliably see internal Kaiten subprocess calls from higher-level scripts.
|
|
124
|
+
|
|
125
|
+
## Local-first Snapshot Layer
|
|
126
|
+
|
|
127
|
+
`snapshot.*` and `query.*` are still registry-defined tools. They differ from transport tools because their `custom` executor path persists and reads local sqlite state in `runtime/snapshots.py`.
|
|
128
|
+
|
|
129
|
+
Current intent:
|
|
130
|
+
|
|
131
|
+
- `snapshot.build` and `snapshot.refresh`
|
|
132
|
+
Fetch a bounded working set from Kaiten once, then persist topology, cards, activity, history, time logs, relations, comments, and derived fields locally.
|
|
133
|
+
- `query.cards`
|
|
134
|
+
Run local filtering and candidate reduction without new API calls. The default local view is `summary`; `detail` and `evidence` are explicit escalations.
|
|
135
|
+
- `query.metrics`
|
|
136
|
+
Compute local metrics over the stored working set instead of rebuilding the same population/history path on every run.
|
|
137
|
+
|
|
138
|
+
This shifts repeated headless analytics from `API-per-question` to `snapshot-per-window`.
|
|
139
|
+
The path stays explicit: normal transport commands are not silently rewritten to snapshot-backed reads.
|
|
140
|
+
The snapshot sqlite store is also treated as disposable derived state: incompatible or corrupt local files are dropped and recreated instead of migrated in place.
|
|
141
|
+
|
|
142
|
+
## Execution Modes
|
|
143
|
+
|
|
144
|
+
- `direct_http`
|
|
145
|
+
One request derived directly from `OperationSpec`.
|
|
146
|
+
- `synthetic`
|
|
147
|
+
Runtime may use fallback logic or reshape API responses to preserve a stable tool contract.
|
|
148
|
+
- `aggregated`
|
|
149
|
+
Runtime performs bounded multi-request collection and returns one logical result.
|
|
150
|
+
- `custom`
|
|
151
|
+
Runtime uses a dedicated executor because the API contract does not map cleanly to a simple request/response flow.
|
|
152
|
+
|
|
153
|
+
`custom` now covers two families:
|
|
154
|
+
|
|
155
|
+
- transport-adjacent orchestration such as batch/history/topology paths
|
|
156
|
+
- local-first snapshot/query paths that do not map to one upstream endpoint
|
|
157
|
+
|
|
158
|
+
Bulk reads are still registry-defined tools. The difference is that some aggregated tools now use a dedicated bulk execution path instead of repeated one-shot CLI invocations. Current examples include `cards.list-all`, `cards.batch-get`, `time-logs.batch-list`, `space-activity-all.get`, `space-topology.get`, `card-children.batch-list`, `comments.batch-list`, and `card-location-history.batch-get`.
|
|
159
|
+
|
|
160
|
+
## Docs Map
|
|
161
|
+
|
|
162
|
+
Primary docs:
|
|
163
|
+
|
|
164
|
+
- [README.md](README.md) for install, usage, config, and operator guidance
|
|
165
|
+
- [COMMAND_REFERENCE.md](COMMAND_REFERENCE.md) for the full generated command catalog
|
|
166
|
+
- [AGENTS.md](AGENTS.md) for agent-specific usage and safety shortcuts
|
|
167
|
+
- `skills/` for repo-local LLM workflows in `SKILL.md` format
|
|
168
|
+
- [LIVE_VALIDATION.md](LIVE_VALIDATION.md) for live test process
|
|
169
|
+
- [API_BEHAVIOR_MATRIX.md](API_BEHAVIOR_MATRIX.md) for documented sandbox contracts
|
|
170
|
+
- `ARCHITECTURE.md` for the system map
|
|
171
|
+
|
|
172
|
+
`ARCHITECTURE_REVIEW.md` is intentionally kept out of tracked docs. It is an audit artifact, not the maintained architecture reference.
|
|
173
|
+
|
|
174
|
+
## Known Tradeoffs
|
|
175
|
+
|
|
176
|
+
- The manual registry is easy to inspect, but large and maintenance-heavy.
|
|
177
|
+
- Runtime behaviors are now explicit, but still centralized in one behavior module.
|
|
178
|
+
- Request-scoped cache is built in, but persistent cache deliberately stays conservative and opt-in.
|
|
179
|
+
- Snapshot refresh is still rebuild-oriented in v1; there is no incremental sync yet.
|
|
180
|
+
- Local metric semantics are still generic; tenant-specific flow profiles are intentionally deferred.
|
|
181
|
+
- The default local card path is intentionally summary-first to reduce token and payload cost before LLM involvement.
|
|
182
|
+
- The CLI favors boundedness and predictability over maximum raw throughput, so bulk execution stays conservative by default.
|
|
183
|
+
- Live validation is explicit and well-documented, but sandbox contracts remain inherently unstable.
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
# Live Validation
|
|
2
|
+
|
|
3
|
+
Этот документ описывает, как устроена полная live-проверка `kaiten-cli` на реальных credentials с явным per-run gate.
|
|
4
|
+
|
|
5
|
+
Текущая матрица контрактов в основном собрана на sandbox tenant, но сам live harness не привязывается к домену, имени профиля или profile metadata автоматически.
|
|
6
|
+
|
|
7
|
+
## Статус проверки
|
|
8
|
+
|
|
9
|
+
- На `2026-07-09` в рамках текущего аудита live suite **не запускался**.
|
|
10
|
+
- Текущий contract baseline — `kaiten-cli v0.1.23`; tenant class ранее зафиксированных контрактов — Kaiten sandbox test tenant.
|
|
11
|
+
- Дата и commit последней полной live campaign не подтверждены в репозитории и остаются `TBD`.
|
|
12
|
+
- До нового запуска [API_BEHAVIOR_MATRIX.md](API_BEHAVIOR_MATRIX.md) описывает ранее наблюдавшиеся и закодированные контракты, а не свежую проверку production или sandbox API.
|
|
13
|
+
|
|
14
|
+
После каждой полной campaign нужно записать в оба документа дату, commit SHA, версию CLI и tenant class, не сохраняя credentials, tenant URL и идентификаторы временных сущностей.
|
|
15
|
+
|
|
16
|
+
## Ограничения пространства
|
|
17
|
+
|
|
18
|
+
Группа `restrictions` — недокументированное расширение по серверному коду, со статусом
|
|
19
|
+
`live_not_validated`. На 2026-10-06 live-сценарий **не запускался**.
|
|
20
|
+
Отдельный opt-in сценарий создаёт два временных пространства, создаёт правило,
|
|
21
|
+
проверяет список и просмотр, отключение и включение с readback, копирование, удаление
|
|
22
|
+
и отсутствие удалённых правил в списках. Cleanup зарегистрирован сразу после создания
|
|
23
|
+
каждого правила и повторно проверяет его отсутствие. Существующие правила не используются.
|
|
24
|
+
Сценарий также включён в полную последовательную campaign.
|
|
25
|
+
|
|
26
|
+
После зелёных локальных проверок и выбора тестовых credentials:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
KAITEN_LIVE=1 python -m pytest -q -m live tests/live/test_restrictions_live.py
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Перед мутациями выполняется `profile probe` в режиме `--read-only`.
|
|
33
|
+
Отдельный сценарий записывает trace в временный каталог pytest. Успешные offline-тесты
|
|
34
|
+
не подтверждают доступность маршрутов на действующем сервере.
|
|
35
|
+
|
|
36
|
+
## Базовые правила
|
|
37
|
+
|
|
38
|
+
- live suite запускается только после зелёного локального `pytest`
|
|
39
|
+
- live suite запускается только при явном `KAITEN_LIVE=1|true`
|
|
40
|
+
- live suite никогда не идёт в default test run
|
|
41
|
+
- выполнение строго последовательное, без параллельных API-вызовов
|
|
42
|
+
- между вызовами остаются паузы для соблюдения low-load discipline
|
|
43
|
+
- все mutation-сценарии обязаны иметь проверяемый teardown
|
|
44
|
+
- если cleanup падает, live test падает
|
|
45
|
+
|
|
46
|
+
## Outcome classes
|
|
47
|
+
|
|
48
|
+
Для live verification используются следующие статусы:
|
|
49
|
+
|
|
50
|
+
- `live_passed`
|
|
51
|
+
Команда реально проходит по success-path на текущем live tenant.
|
|
52
|
+
- `live_passed_with_runtime_fix`
|
|
53
|
+
Команда проходит на текущем live tenant, но для этого понадобился runtime shaping в CLI.
|
|
54
|
+
- `live_passed_as_expected_error`
|
|
55
|
+
Живой API стабильно или условно возвращает ожидаемый `4xx`, и этот контракт проверяется как корректный.
|
|
56
|
+
- `synthetic_read`
|
|
57
|
+
Прямой endpoint нестабилен или unsupported, но CLI честно собирает эквивалентный read из другого безопасного endpoint.
|
|
58
|
+
- `policy_excluded`
|
|
59
|
+
Команда сознательно исключена из live validation по политике безопасности.
|
|
60
|
+
- `live_not_validated`
|
|
61
|
+
Команда добавлена после последней полной campaign. В live suite сценарий для неё есть, но
|
|
62
|
+
реального прогона, подтверждающего контракт, ещё не было.
|
|
63
|
+
|
|
64
|
+
## Что считается успешной live-валидацией
|
|
65
|
+
|
|
66
|
+
Команда считается live-covered только если выполнено одно из условий:
|
|
67
|
+
|
|
68
|
+
1. success-path реально отработал и postcondition подтверждён;
|
|
69
|
+
2. documented expected-error-path реально отработал и статус соответствует контракту;
|
|
70
|
+
3. synthetic fallback реально отработал и вернул ожидаемые данные;
|
|
71
|
+
4. команда помечена `policy_excluded`.
|
|
72
|
+
|
|
73
|
+
Статус `live_not_validated` покрытием не считается: он честно фиксирует, что сценарий в
|
|
74
|
+
harness уже написан, но прогона ещё не было.
|
|
75
|
+
|
|
76
|
+
Скрытых “ну это вроде нормально” сценариев быть не должно.
|
|
77
|
+
|
|
78
|
+
## Как устроен live harness
|
|
79
|
+
|
|
80
|
+
Файлы:
|
|
81
|
+
|
|
82
|
+
- [tests/live/conftest.py](tests/live/conftest.py)
|
|
83
|
+
- [tests/live/test_sandbox_live_full.py](tests/live/test_sandbox_live_full.py)
|
|
84
|
+
|
|
85
|
+
Harness делает следующее:
|
|
86
|
+
|
|
87
|
+
- создаёт run-scoped имена временных сущностей
|
|
88
|
+
- ведёт cleanup stack в обратном порядке
|
|
89
|
+
- использует только canonical commands для live coverage
|
|
90
|
+
- считает покрытие по всему registry surface, кроме policy exclusions
|
|
91
|
+
- различает normal success path и expected-error path
|
|
92
|
+
|
|
93
|
+
## Policy exclusions
|
|
94
|
+
|
|
95
|
+
Сейчас live validation не включает:
|
|
96
|
+
|
|
97
|
+
- `api-keys.create`
|
|
98
|
+
- `api-keys.delete`
|
|
99
|
+
|
|
100
|
+
Причина: clean teardown невозможен без тестирования удаления ключей, а удаление ключей пользователь запретил проверять live.
|
|
101
|
+
|
|
102
|
+
## Synthetic contracts
|
|
103
|
+
|
|
104
|
+
Явные synthetic reads:
|
|
105
|
+
|
|
106
|
+
- `projects.cards.list`
|
|
107
|
+
- сначала CLI пробует `GET /projects/{project_id}/cards`
|
|
108
|
+
- если live API отвечает `405`, CLI делает `GET /projects/{project_id}?with_cards_data=true`
|
|
109
|
+
- затем извлекает embedded cards list из project payload
|
|
110
|
+
- `checklists.list`
|
|
111
|
+
- direct `GET /cards/{card_id}/checklists` возвращает `405`
|
|
112
|
+
- CLI делает `GET /cards/{card_id}` и извлекает embedded `checklists`
|
|
113
|
+
- `checklist-items.list`
|
|
114
|
+
- direct `GET /cards/{card_id}/checklists/{checklist_id}/items` возвращает `405`
|
|
115
|
+
- CLI делает `GET /cards/{card_id}` и извлекает `items` из matching checklist
|
|
116
|
+
|
|
117
|
+
## Expected-error contracts
|
|
118
|
+
|
|
119
|
+
Некоторые команды считаются live-correct именно через documented `4xx`:
|
|
120
|
+
|
|
121
|
+
- `removed-boards.list` -> `405`
|
|
122
|
+
- `removed-cards.list` -> `405`
|
|
123
|
+
- `card-subscribers.list` -> `405`
|
|
124
|
+
- `column-subscribers.list` -> `405`
|
|
125
|
+
|
|
126
|
+
Есть и условные tenant'ы, где live API может разрешить success-path или вернуть ожидаемый `4xx`:
|
|
127
|
+
|
|
128
|
+
- `automations.copy`
|
|
129
|
+
- `sprints.*`
|
|
130
|
+
- `workflows.*`
|
|
131
|
+
- `service-desk.requests.*`
|
|
132
|
+
- `service-desk.sla-rules.*`
|
|
133
|
+
- `user-timers.*`
|
|
134
|
+
- `compute-jobs.cancel`
|
|
135
|
+
|
|
136
|
+
Отдельно зафиксирован automation contract:
|
|
137
|
+
|
|
138
|
+
- `automations.create` и `automations.update` проходят на success-path при e2e-shaped payload:
|
|
139
|
+
- `trigger.type = card_created`
|
|
140
|
+
- `action.type = add_assignee`
|
|
141
|
+
- `action.created = <iso datetime>`
|
|
142
|
+
- `action.data.variant = specific`
|
|
143
|
+
- `action.data.userId = <current_user_id>`
|
|
144
|
+
- `automations.get` может возвращать `405` даже после успешного create
|
|
145
|
+
- `automations.copy` остаётся conditional sandbox contract
|
|
146
|
+
|
|
147
|
+
Также зафиксирован ещё один стабильный expected-error:
|
|
148
|
+
|
|
149
|
+
- `service-desk.users.update` -> `400`, если текущий live-пользователь не является Service Desk user
|
|
150
|
+
|
|
151
|
+
И один смешанный Service Desk contract:
|
|
152
|
+
|
|
153
|
+
- `service-desk.users.set-temp-password` может либо успешно отработать, либо вернуть `403/404/405`
|
|
154
|
+
- `service-desk.organization-users.update` может либо успешно отработать, либо вернуть `400/403/404/405` даже после успешного `organization-users.add`
|
|
155
|
+
|
|
156
|
+
Точные статусы и примечания см. в [API_BEHAVIOR_MATRIX.md](API_BEHAVIOR_MATRIX.md).
|
|
157
|
+
|
|
158
|
+
## Запуск
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
KAITEN_LIVE=true KAITEN_DOMAIN=<company-subdomain-or-url> KAITEN_TOKEN=... \
|
|
162
|
+
.venv/bin/pytest -m live -o addopts='--disable-socket --allow-unix-socket' \
|
|
163
|
+
tests/live/test_sandbox_live_full.py
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Если credentials уже сохранены в обычном active profile, достаточно выставить только `KAITEN_LIVE=1|true`.
|
|
167
|
+
|
|
168
|
+
## Что делать при новом blocker-е
|
|
169
|
+
|
|
170
|
+
1. Сначала определить, это runtime bug, live API limitation или synthetic-fallback candidate.
|
|
171
|
+
2. Если это runtime bug — добавить/обновить offline test и чинить CLI.
|
|
172
|
+
3. Если это корректный expected error — зафиксировать его в `API_BEHAVIOR_MATRIX.md` и, если меняется объяснение системы, в `ARCHITECTURE.md`.
|
|
173
|
+
4. Если это честный synthetic candidate — сначала добавить failing offline test, потом реализовать fallback.
|
|
174
|
+
|
|
175
|
+
## Изменения чтения чеклистов
|
|
176
|
+
|
|
177
|
+
`checklists.list` читает `GET /cards/{card_id}` и извлекает `checklists`.
|
|
178
|
+
Collection GET возвращал 405 на тестовом инстансе; такое же поведение на боевом
|
|
179
|
+
инстансе описано автором [kaiten-mcp PR #4](https://github.com/ViktorOgnev/kaiten-mcp/pull/4).
|
|
180
|
+
Это свидетельство автора PR, а не новая live-проверка CLI.
|
|
181
|
+
|
|
182
|
+
`checklist-items.list` теперь читает `GET /cards/{card_id}/checklists/{checklist_id}`
|
|
183
|
+
и извлекает `items`. Пустой чеклист возвращает `[]`, а ошибки API, включая 404,
|
|
184
|
+
сохраняются. Некорректный ответ без массива `items` считается ошибкой транспорта.
|
|
185
|
+
Оба обхода применяются ко всем профилям; тестовый инстанс — место наблюдения,
|
|
186
|
+
а не особый режим CLI. Изменение проверено офлайн через HTTP-моки.
|