tktl-cli 0.1.0a1__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.
- tktl_cli-0.1.0a1/.github/workflows/ci.yml +69 -0
- tktl_cli-0.1.0a1/.github/workflows/publish.yml +68 -0
- tktl_cli-0.1.0a1/.gitignore +11 -0
- tktl_cli-0.1.0a1/ADR.md +246 -0
- tktl_cli-0.1.0a1/AGENTS.md +106 -0
- tktl_cli-0.1.0a1/CLAUDE.md +21 -0
- tktl_cli-0.1.0a1/PKG-INFO +11 -0
- tktl_cli-0.1.0a1/README.md +185 -0
- tktl_cli-0.1.0a1/docs/plans/done-plan-core-initial.md +334 -0
- tktl_cli-0.1.0a1/docs/plans/plan-render.md +53 -0
- tktl_cli-0.1.0a1/docs/plans/plan-repo-restructure.md +31 -0
- tktl_cli-0.1.0a1/docs/plans/posthog-instrumentation.md +206 -0
- tktl_cli-0.1.0a1/docs/specs/batch-run.md +697 -0
- tktl_cli-0.1.0a1/docs/specs/core-implementation.md +1588 -0
- tktl_cli-0.1.0a1/docs/specs/datasets.md +605 -0
- tktl_cli-0.1.0a1/docs/specs/flow-review.md +44 -0
- tktl_cli-0.1.0a1/docs/specs/posthog-instrumentation.md +383 -0
- tktl_cli-0.1.0a1/docs/specs/render.md +173 -0
- tktl_cli-0.1.0a1/pyproject.toml +60 -0
- tktl_cli-0.1.0a1/scripts/install-hooks.py +24 -0
- tktl_cli-0.1.0a1/scripts/pre-commit +13 -0
- tktl_cli-0.1.0a1/skills/create-flow/SKILL.md +419 -0
- tktl_cli-0.1.0a1/skills/diff-flow-versions/SKILL.md +66 -0
- tktl_cli-0.1.0a1/skills/flow-builder/SKILL.md +537 -0
- tktl_cli-0.1.0a1/skills/flow-builder/references/debugging.md +134 -0
- tktl_cli-0.1.0a1/skills/flow-builder/references/executing-flows-and-local-testing.md +338 -0
- tktl_cli-0.1.0a1/skills/flow-builder/references/flow-patterns.md +137 -0
- tktl_cli-0.1.0a1/skills/flow-builder/references/node-configs.md +242 -0
- tktl_cli-0.1.0a1/skills/flow-builder/references/working-with-child-flows-and-loop-nodes.md +308 -0
- tktl_cli-0.1.0a1/skills/flow-context/SKILL.md +559 -0
- tktl_cli-0.1.0a1/skills/flow-review/SKILL.md +456 -0
- tktl_cli-0.1.0a1/skills/flow-review/references/best-practices.md +226 -0
- tktl_cli-0.1.0a1/skills/flow-review/references/improvements.md +22 -0
- tktl_cli-0.1.0a1/skills/flow-review/references/known-issues.md +109 -0
- tktl_cli-0.1.0a1/skills/flow-summary/SKILL.md +168 -0
- tktl_cli-0.1.0a1/skills/onboard-flow/SKILL.md +280 -0
- tktl_cli-0.1.0a1/skills/tktl-debug/SKILL.md +579 -0
- tktl_cli-0.1.0a1/src/tktl/__init__.py +0 -0
- tktl_cli-0.1.0a1/src/tktl/api/__init__.py +29 -0
- tktl_cli-0.1.0a1/src/tktl/api/client.py +154 -0
- tktl_cli-0.1.0a1/src/tktl/api/comments.py +99 -0
- tktl_cli-0.1.0a1/src/tktl/api/connections.py +86 -0
- tktl_cli-0.1.0a1/src/tktl/api/datasets.py +502 -0
- tktl_cli-0.1.0a1/src/tktl/api/execution.py +186 -0
- tktl_cli-0.1.0a1/src/tktl/api/flows.py +75 -0
- tktl_cli-0.1.0a1/src/tktl/api/folders.py +45 -0
- tktl_cli-0.1.0a1/src/tktl/api/versions.py +383 -0
- tktl_cli-0.1.0a1/src/tktl/cache/__init__.py +12 -0
- tktl_cli-0.1.0a1/src/tktl/cache/freshness.py +33 -0
- tktl_cli-0.1.0a1/src/tktl/cache/index.py +110 -0
- tktl_cli-0.1.0a1/src/tktl/cache/manager.py +197 -0
- tktl_cli-0.1.0a1/src/tktl/cli/__init__.py +0 -0
- tktl_cli-0.1.0a1/src/tktl/cli/_deps.py +79 -0
- tktl_cli-0.1.0a1/src/tktl/cli/_error_handler.py +41 -0
- tktl_cli-0.1.0a1/src/tktl/cli/_json_arg.py +32 -0
- tktl_cli-0.1.0a1/src/tktl/cli/auth.py +112 -0
- tktl_cli-0.1.0a1/src/tktl/cli/cache_cmd.py +48 -0
- tktl_cli-0.1.0a1/src/tktl/cli/comments.py +58 -0
- tktl_cli-0.1.0a1/src/tktl/cli/config_cmd.py +42 -0
- tktl_cli-0.1.0a1/src/tktl/cli/connections.py +122 -0
- tktl_cli-0.1.0a1/src/tktl/cli/datasets.py +309 -0
- tktl_cli-0.1.0a1/src/tktl/cli/flows.py +490 -0
- tktl_cli-0.1.0a1/src/tktl/cli/folders.py +37 -0
- tktl_cli-0.1.0a1/src/tktl/cli/groups.py +173 -0
- tktl_cli-0.1.0a1/src/tktl/cli/init_cmd.py +130 -0
- tktl_cli-0.1.0a1/src/tktl/cli/main.py +85 -0
- tktl_cli-0.1.0a1/src/tktl/cli/nodes.py +245 -0
- tktl_cli-0.1.0a1/src/tktl/cli/output.py +155 -0
- tktl_cli-0.1.0a1/src/tktl/cli/render_cmd.py +68 -0
- tktl_cli-0.1.0a1/src/tktl/cli/run.py +45 -0
- tktl_cli-0.1.0a1/src/tktl/cli/update.py +89 -0
- tktl_cli-0.1.0a1/src/tktl/cli/versions.py +223 -0
- tktl_cli-0.1.0a1/src/tktl/config.py +113 -0
- tktl_cli-0.1.0a1/src/tktl/merge.py +27 -0
- tktl_cli-0.1.0a1/src/tktl/models/__init__.py +24 -0
- tktl_cli-0.1.0a1/src/tktl/models/batch.py +59 -0
- tktl_cli-0.1.0a1/src/tktl/models/connection.py +43 -0
- tktl_cli-0.1.0a1/src/tktl/models/dataset.py +141 -0
- tktl_cli-0.1.0a1/src/tktl/models/diff.py +136 -0
- tktl_cli-0.1.0a1/src/tktl/models/errors.py +43 -0
- tktl_cli-0.1.0a1/src/tktl/models/flow.py +25 -0
- tktl_cli-0.1.0a1/src/tktl/models/folder.py +20 -0
- tktl_cli-0.1.0a1/src/tktl/models/group.py +22 -0
- tktl_cli-0.1.0a1/src/tktl/models/node.py +24 -0
- tktl_cli-0.1.0a1/src/tktl/models/version.py +28 -0
- tktl_cli-0.1.0a1/src/tktl/ops/__init__.py +64 -0
- tktl_cli-0.1.0a1/src/tktl/ops/batch.py +611 -0
- tktl_cli-0.1.0a1/src/tktl/ops/cache_ops.py +121 -0
- tktl_cli-0.1.0a1/src/tktl/ops/comments.py +119 -0
- tktl_cli-0.1.0a1/src/tktl/ops/connections.py +88 -0
- tktl_cli-0.1.0a1/src/tktl/ops/datasets.py +546 -0
- tktl_cli-0.1.0a1/src/tktl/ops/diff.py +668 -0
- tktl_cli-0.1.0a1/src/tktl/ops/explain.py +162 -0
- tktl_cli-0.1.0a1/src/tktl/ops/flows.py +234 -0
- tktl_cli-0.1.0a1/src/tktl/ops/folders.py +45 -0
- tktl_cli-0.1.0a1/src/tktl/ops/graph.py +489 -0
- tktl_cli-0.1.0a1/src/tktl/ops/groups.py +265 -0
- tktl_cli-0.1.0a1/src/tktl/ops/manual_review.py +88 -0
- tktl_cli-0.1.0a1/src/tktl/ops/nodes.py +290 -0
- tktl_cli-0.1.0a1/src/tktl/ops/render.py +903 -0
- tktl_cli-0.1.0a1/src/tktl/ops/rule_parser.py +207 -0
- tktl_cli-0.1.0a1/src/tktl/ops/templates.py +399 -0
- tktl_cli-0.1.0a1/src/tktl/ops/versions.py +575 -0
- tktl_cli-0.1.0a1/src/tktl/resolver.py +121 -0
- tktl_cli-0.1.0a1/src/tktl/telemetry.py +199 -0
- tktl_cli-0.1.0a1/tests/__init__.py +0 -0
- tktl_cli-0.1.0a1/tests/conftest.py +192 -0
- tktl_cli-0.1.0a1/tests/fake_api/__init__.py +0 -0
- tktl_cli-0.1.0a1/tests/fake_api/app.py +118 -0
- tktl_cli-0.1.0a1/tests/fake_api/data/monitoring.json +1443 -0
- tktl_cli-0.1.0a1/tests/fake_api/data/simple.json +300 -0
- tktl_cli-0.1.0a1/tests/fake_api/merge_patch.py +19 -0
- tktl_cli-0.1.0a1/tests/fake_api/routes.py +982 -0
- tktl_cli-0.1.0a1/tests/fake_api/seed.py +178 -0
- tktl_cli-0.1.0a1/tests/fake_api/state.py +130 -0
- tktl_cli-0.1.0a1/tests/fake_api/test_merge_patch.py +45 -0
- tktl_cli-0.1.0a1/tests/fake_api/test_routes.py +252 -0
- tktl_cli-0.1.0a1/tests/test_api/__init__.py +0 -0
- tktl_cli-0.1.0a1/tests/test_api/conftest.py +64 -0
- tktl_cli-0.1.0a1/tests/test_api/test_client.py +247 -0
- tktl_cli-0.1.0a1/tests/test_api/test_comments.py +86 -0
- tktl_cli-0.1.0a1/tests/test_api/test_dataset_upload.py +73 -0
- tktl_cli-0.1.0a1/tests/test_api/test_datasets.py +88 -0
- tktl_cli-0.1.0a1/tests/test_api/test_datasets_crud.py +266 -0
- tktl_cli-0.1.0a1/tests/test_api/test_execution.py +181 -0
- tktl_cli-0.1.0a1/tests/test_api/test_flows.py +73 -0
- tktl_cli-0.1.0a1/tests/test_api/test_versions.py +351 -0
- tktl_cli-0.1.0a1/tests/test_cache/__init__.py +0 -0
- tktl_cli-0.1.0a1/tests/test_cache/test_freshness.py +53 -0
- tktl_cli-0.1.0a1/tests/test_cache/test_index.py +125 -0
- tktl_cli-0.1.0a1/tests/test_cache/test_manager.py +296 -0
- tktl_cli-0.1.0a1/tests/test_cli/__init__.py +0 -0
- tktl_cli-0.1.0a1/tests/test_cli/conftest.py +151 -0
- tktl_cli-0.1.0a1/tests/test_cli/test_agent.py +120 -0
- tktl_cli-0.1.0a1/tests/test_cli/test_auth.py +59 -0
- tktl_cli-0.1.0a1/tests/test_cli/test_batch.py +391 -0
- tktl_cli-0.1.0a1/tests/test_cli/test_cache_cmd.py +50 -0
- tktl_cli-0.1.0a1/tests/test_cli/test_changes.py +39 -0
- tktl_cli-0.1.0a1/tests/test_cli/test_comments.py +77 -0
- tktl_cli-0.1.0a1/tests/test_cli/test_config.py +31 -0
- tktl_cli-0.1.0a1/tests/test_cli/test_connections.py +192 -0
- tktl_cli-0.1.0a1/tests/test_cli/test_datasets.py +205 -0
- tktl_cli-0.1.0a1/tests/test_cli/test_diff.py +49 -0
- tktl_cli-0.1.0a1/tests/test_cli/test_errors.py +143 -0
- tktl_cli-0.1.0a1/tests/test_cli/test_flows.py +61 -0
- tktl_cli-0.1.0a1/tests/test_cli/test_flows_batch_feedback.py +235 -0
- tktl_cli-0.1.0a1/tests/test_cli/test_flows_explain.py +71 -0
- tktl_cli-0.1.0a1/tests/test_cli/test_flows_template.py +124 -0
- tktl_cli-0.1.0a1/tests/test_cli/test_flows_wizard.py +61 -0
- tktl_cli-0.1.0a1/tests/test_cli/test_groups.py +147 -0
- tktl_cli-0.1.0a1/tests/test_cli/test_init.py +124 -0
- tktl_cli-0.1.0a1/tests/test_cli/test_lifecycle.py +54 -0
- tktl_cli-0.1.0a1/tests/test_cli/test_nodes.py +454 -0
- tktl_cli-0.1.0a1/tests/test_cli/test_nodes_edit.py +78 -0
- tktl_cli-0.1.0a1/tests/test_cli/test_output.py +239 -0
- tktl_cli-0.1.0a1/tests/test_cli/test_render.py +103 -0
- tktl_cli-0.1.0a1/tests/test_cli/test_rule_parser.py +130 -0
- tktl_cli-0.1.0a1/tests/test_cli/test_run.py +82 -0
- tktl_cli-0.1.0a1/tests/test_cli/test_update.py +198 -0
- tktl_cli-0.1.0a1/tests/test_cli/test_versions.py +102 -0
- tktl_cli-0.1.0a1/tests/test_cli/test_versions_diff.py +86 -0
- tktl_cli-0.1.0a1/tests/test_concurrency/__init__.py +0 -0
- tktl_cli-0.1.0a1/tests/test_concurrency/conftest.py +51 -0
- tktl_cli-0.1.0a1/tests/test_concurrency/test_etag_retry.py +165 -0
- tktl_cli-0.1.0a1/tests/test_concurrency/test_locks.py +138 -0
- tktl_cli-0.1.0a1/tests/test_config.py +100 -0
- tktl_cli-0.1.0a1/tests/test_e2e/__init__.py +0 -0
- tktl_cli-0.1.0a1/tests/test_e2e/conftest.py +5 -0
- tktl_cli-0.1.0a1/tests/test_e2e/test_bulk_replace.py +109 -0
- tktl_cli-0.1.0a1/tests/test_e2e/test_etag_retry.py +96 -0
- tktl_cli-0.1.0a1/tests/test_e2e/test_lifecycle.py +112 -0
- tktl_cli-0.1.0a1/tests/test_e2e/test_monitoring_flow.py +510 -0
- tktl_cli-0.1.0a1/tests/test_e2e/test_read_flow.py +108 -0
- tktl_cli-0.1.0a1/tests/test_e2e/test_update_node.py +128 -0
- tktl_cli-0.1.0a1/tests/test_e2e/test_update_version.py +132 -0
- tktl_cli-0.1.0a1/tests/test_integration/__init__.py +0 -0
- tktl_cli-0.1.0a1/tests/test_integration/conftest.py +98 -0
- tktl_cli-0.1.0a1/tests/test_integration/test_batch_run.py +171 -0
- tktl_cli-0.1.0a1/tests/test_integration/test_build_and_run_flow.py +259 -0
- tktl_cli-0.1.0a1/tests/test_integration/test_dev_environment.py +274 -0
- tktl_cli-0.1.0a1/tests/test_integration/test_graph_lifecycle.py +419 -0
- tktl_cli-0.1.0a1/tests/test_integration/test_incremental_build.py +411 -0
- tktl_cli-0.1.0a1/tests/test_integration/test_modify_flow.py +279 -0
- tktl_cli-0.1.0a1/tests/test_integration/test_subflow_mocking.py +322 -0
- tktl_cli-0.1.0a1/tests/test_integration/test_tomtest_flow.py +272 -0
- tktl_cli-0.1.0a1/tests/test_merge.py +127 -0
- tktl_cli-0.1.0a1/tests/test_models/__init__.py +0 -0
- tktl_cli-0.1.0a1/tests/test_models/test_batch.py +172 -0
- tktl_cli-0.1.0a1/tests/test_models/test_dataset.py +201 -0
- tktl_cli-0.1.0a1/tests/test_models/test_errors.py +59 -0
- tktl_cli-0.1.0a1/tests/test_models/test_flow.py +46 -0
- tktl_cli-0.1.0a1/tests/test_models/test_group.py +40 -0
- tktl_cli-0.1.0a1/tests/test_models/test_node.py +28 -0
- tktl_cli-0.1.0a1/tests/test_models/test_version.py +55 -0
- tktl_cli-0.1.0a1/tests/test_ops/__init__.py +0 -0
- tktl_cli-0.1.0a1/tests/test_ops/conftest.py +53 -0
- tktl_cli-0.1.0a1/tests/test_ops/test_batch.py +508 -0
- tktl_cli-0.1.0a1/tests/test_ops/test_cache_ops.py +100 -0
- tktl_cli-0.1.0a1/tests/test_ops/test_datasets.py +277 -0
- tktl_cli-0.1.0a1/tests/test_ops/test_diff.py +285 -0
- tktl_cli-0.1.0a1/tests/test_ops/test_flows.py +82 -0
- tktl_cli-0.1.0a1/tests/test_ops/test_graph.py +166 -0
- tktl_cli-0.1.0a1/tests/test_ops/test_groups.py +282 -0
- tktl_cli-0.1.0a1/tests/test_ops/test_manual_review.py +101 -0
- tktl_cli-0.1.0a1/tests/test_ops/test_node_update.py +226 -0
- tktl_cli-0.1.0a1/tests/test_ops/test_nodes.py +140 -0
- tktl_cli-0.1.0a1/tests/test_ops/test_render.py +667 -0
- tktl_cli-0.1.0a1/tests/test_ops/test_run.py +108 -0
- tktl_cli-0.1.0a1/tests/test_ops/test_telemetry.py +454 -0
- tktl_cli-0.1.0a1/tests/test_ops/test_version_lifecycle.py +102 -0
- tktl_cli-0.1.0a1/tests/test_ops/test_version_replace.py +70 -0
- tktl_cli-0.1.0a1/tests/test_ops/test_version_update.py +103 -0
- tktl_cli-0.1.0a1/tests/test_ops/test_versions.py +344 -0
- tktl_cli-0.1.0a1/tests/test_resolver.py +181 -0
- tktl_cli-0.1.0a1/tests/test_smoke.py +16 -0
- tktl_cli-0.1.0a1/tests/test_telemetry.py +279 -0
- tktl_cli-0.1.0a1/uv.lock +832 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
lint:
|
|
10
|
+
runs-on: [self-hosted, ub-arm-2core-ue2]
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
|
13
|
+
- uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
|
|
14
|
+
- run: uv sync
|
|
15
|
+
- run: uv run ruff check .
|
|
16
|
+
- run: uv run ruff format --check .
|
|
17
|
+
- run: uv run ty check src/ tests/
|
|
18
|
+
|
|
19
|
+
test:
|
|
20
|
+
runs-on: [self-hosted, ub-arm-2core-ue2]
|
|
21
|
+
steps:
|
|
22
|
+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
|
23
|
+
- uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
|
|
24
|
+
- run: uv sync
|
|
25
|
+
- run: uv run pytest -x -v --ignore=tests/test_integration
|
|
26
|
+
|
|
27
|
+
package:
|
|
28
|
+
runs-on: [self-hosted, ub-arm-2core-ue2]
|
|
29
|
+
steps:
|
|
30
|
+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
|
31
|
+
- uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
|
|
32
|
+
- run: uv build
|
|
33
|
+
- name: Verify no sensitive files in wheel
|
|
34
|
+
run: |
|
|
35
|
+
WHEEL=$(ls dist/*.whl)
|
|
36
|
+
FOUND=$(unzip -l "$WHEEL" | grep -cE '(openapi/|templates/.*\.json|\.env)' || true)
|
|
37
|
+
if [ "$FOUND" -ne 0 ]; then
|
|
38
|
+
echo "::error::Wheel contains excluded files:"
|
|
39
|
+
unzip -l "$WHEEL" | grep -E '(openapi/|templates/.*\.json|\.env)'
|
|
40
|
+
exit 1
|
|
41
|
+
fi
|
|
42
|
+
- name: Verify no sensitive files in sdist
|
|
43
|
+
run: |
|
|
44
|
+
SDIST=$(ls dist/*.tar.gz)
|
|
45
|
+
FOUND=$(tar tzf "$SDIST" | grep -cE '(openapi/|templates/.*\.json|\.env)' || true)
|
|
46
|
+
if [ "$FOUND" -ne 0 ]; then
|
|
47
|
+
echo "::error::Sdist contains excluded files:"
|
|
48
|
+
tar tzf "$SDIST" | grep -E '(openapi/|templates/.*\.json|\.env)'
|
|
49
|
+
exit 1
|
|
50
|
+
fi
|
|
51
|
+
|
|
52
|
+
integration:
|
|
53
|
+
runs-on: [self-hosted, ub-arm-2core-ue2]
|
|
54
|
+
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
|
55
|
+
needs: [lint, test]
|
|
56
|
+
env:
|
|
57
|
+
TKTL_DEV_API_KEY: ${{ secrets.TKTL_DEV_API_KEY }}
|
|
58
|
+
steps:
|
|
59
|
+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
|
60
|
+
- uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
|
|
61
|
+
- run: uv sync
|
|
62
|
+
- name: Verify API key is set
|
|
63
|
+
run: |
|
|
64
|
+
if [ -z "$TKTL_DEV_API_KEY" ]; then
|
|
65
|
+
echo "::error::TKTL_DEV_API_KEY is not set. Add DEV_API_KEY as a repository secret."
|
|
66
|
+
exit 1
|
|
67
|
+
fi
|
|
68
|
+
echo "API key is configured (${#TKTL_DEV_API_KEY} chars)"
|
|
69
|
+
- run: uv run pytest tests/test_integration -v --tb=short
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags: ["v*"]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
lint:
|
|
9
|
+
runs-on: [self-hosted, ub-arm-2core-ue2]
|
|
10
|
+
steps:
|
|
11
|
+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
|
12
|
+
- uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
|
|
13
|
+
- run: uv sync
|
|
14
|
+
- run: uv run ruff check .
|
|
15
|
+
- run: uv run ruff format --check .
|
|
16
|
+
- run: uv run ty check src/ tests/
|
|
17
|
+
|
|
18
|
+
test:
|
|
19
|
+
runs-on: [self-hosted, ub-arm-2core-ue2]
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
|
22
|
+
- uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
|
|
23
|
+
- run: uv sync
|
|
24
|
+
- run: uv run pytest -x -v --ignore=tests/test_integration
|
|
25
|
+
|
|
26
|
+
build:
|
|
27
|
+
runs-on: [self-hosted, ub-arm-2core-ue2]
|
|
28
|
+
needs: [lint, test]
|
|
29
|
+
steps:
|
|
30
|
+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
|
31
|
+
- uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
|
|
32
|
+
- run: uv build
|
|
33
|
+
- name: Verify no sensitive files in wheel
|
|
34
|
+
run: |
|
|
35
|
+
WHEEL=$(ls dist/*.whl)
|
|
36
|
+
FOUND=$(unzip -l "$WHEEL" | grep -cE '(openapi/|templates/.*\.json|\.env)' || true)
|
|
37
|
+
if [ "$FOUND" -ne 0 ]; then
|
|
38
|
+
echo "::error::Wheel contains excluded files:"
|
|
39
|
+
unzip -l "$WHEEL" | grep -E '(openapi/|templates/.*\.json|\.env)'
|
|
40
|
+
exit 1
|
|
41
|
+
fi
|
|
42
|
+
- name: Verify no sensitive files in sdist
|
|
43
|
+
run: |
|
|
44
|
+
SDIST=$(ls dist/*.tar.gz)
|
|
45
|
+
FOUND=$(tar tzf "$SDIST" | grep -cE '(openapi/|templates/.*\.json|\.env)' || true)
|
|
46
|
+
if [ "$FOUND" -ne 0 ]; then
|
|
47
|
+
echo "::error::Sdist contains excluded files:"
|
|
48
|
+
tar tzf "$SDIST" | grep -E '(openapi/|templates/.*\.json|\.env)'
|
|
49
|
+
exit 1
|
|
50
|
+
fi
|
|
51
|
+
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
|
52
|
+
with:
|
|
53
|
+
name: dist
|
|
54
|
+
path: dist/
|
|
55
|
+
|
|
56
|
+
publish:
|
|
57
|
+
runs-on: [self-hosted, ub-arm-2core-ue2]
|
|
58
|
+
needs: [build]
|
|
59
|
+
environment: pypi
|
|
60
|
+
permissions:
|
|
61
|
+
id-token: write
|
|
62
|
+
steps:
|
|
63
|
+
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
|
64
|
+
with:
|
|
65
|
+
name: dist
|
|
66
|
+
path: dist/
|
|
67
|
+
- uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
|
|
68
|
+
- run: uv publish --trusted-publishing always dist/*
|
tktl_cli-0.1.0a1/ADR.md
ADDED
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
# ADR: tktl CLI Architecture Decisions
|
|
2
|
+
|
|
3
|
+
> **Legend:** 🔶 = work-in-progress or planned
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Context
|
|
8
|
+
|
|
9
|
+
- We want agents to author and test flows, as per Q2 2026 OKR
|
|
10
|
+
- [We built a set of tools (CLI + skill) for agentic whole flow authoring that have at least 10 internal and 2 external weekly users. All functionality is built in such a way that they can be integrated into an on-platform copilot on the Agents infrastructure in Q3'26.](https://www.notion.so/We-built-a-set-of-tools-CLI-skill-for-agentic-whole-flow-authoring-that-have-at-least-10-interna-32f0a226e5be80f3a1c2d51a7f8d7fd5?pvs=21)
|
|
11
|
+
- Three consumer types need the same operations:
|
|
12
|
+
- Humans in terminals
|
|
13
|
+
- Automation scripts (automated updates, rollouts)
|
|
14
|
+
- Agents: local (Claude Code/Codex) and on-platform (hosted agent runtime)
|
|
15
|
+
- We need to support large flow editing
|
|
16
|
+
- Flow versions can contain thousands of nodes, producing 10,000+ line JSON on GET
|
|
17
|
+
- The Flow API has no node-level endpoints. Nodes are embedded in the version graph
|
|
18
|
+
- PATCH requires the full node set in the body (otherwise 409)
|
|
19
|
+
- Multiple users and agents may edit the same flow version concurrently
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Principles
|
|
24
|
+
|
|
25
|
+
**We optimize for**
|
|
26
|
+
|
|
27
|
+
- **Agent efficiency:** surgical operations + auto-JSON + cache decomposition keep context windows small
|
|
28
|
+
- **Zero code duplication:** one ops layer serves CLI, agents, scripts, and future interfaces
|
|
29
|
+
- **Simple concurrency:** ETag retries + node locks, invisible to the user, prevent data loss
|
|
30
|
+
- **Composability:** every command produces structured JSON for shell pipelines and automation
|
|
31
|
+
- **Low token cost:** `--summary`, `--section`, per-node cache files minimize data transferred to agents
|
|
32
|
+
- **Fast iteration:** APIs are stable, CLI and skill can change faster, especially during internal testing
|
|
33
|
+
- **Agents code:** we embrace agent coding, kept on point from specification files in repository
|
|
34
|
+
|
|
35
|
+
**We accept**
|
|
36
|
+
|
|
37
|
+
- **Client-side node extraction:** the CLI must fetch and decompose the full version graph. Cache mitigates this but first-fetch is expensive
|
|
38
|
+
- 🔶 **Internal Flow API exposure:** should be moved to public-facing workspace API before public release
|
|
39
|
+
- **Cache staleness risk:** 5-minute TTL can serve stale data. ETag validation on writes catches this but reads may be outdated
|
|
40
|
+
- 🔶 **Local tooling assumption:** the design leans on `jq`, `grep`, `diff` and filesystem access. Risk for on-platform runtime where bash is not exposed
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Decision
|
|
45
|
+
|
|
46
|
+
### 1. Repo code structure
|
|
47
|
+
|
|
48
|
+
#### 1.1 Library-first, CLI as interface
|
|
49
|
+
|
|
50
|
+
- All business logic in `tktl.ops` as importable Python functions
|
|
51
|
+
- CLI (`tktl.cli`) is a thin Typer wrapper: parse args → call ops → format output
|
|
52
|
+
- No business logic in the CLI layer, ever
|
|
53
|
+
- Three access modes from the same code: CLI, Python import, MCP tool
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
tktl.cli → Typer (arg parsing + output formatting only)
|
|
57
|
+
tktl.ops → business logic, caching, locking, ID resolution
|
|
58
|
+
tktl.api → hand-written HTTP orchestration (auth, headers, retries)
|
|
59
|
+
tktl.generated → auto-generated from OpenAPI (never edit)
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
#### 1.2 CLI as primary interface, not MCP
|
|
63
|
+
|
|
64
|
+
We expose 60+ commands across 13 resource groups, growing. At that scale, CLI beats MCP:
|
|
65
|
+
|
|
66
|
+
- **Zero schema bloat.** MCP injects every tool's schema upfront (thousands of tokens). CLI has zero upfront cost, agent calls `--help` on demand.
|
|
67
|
+
- **Shell composability.** `tktl nodes list credit-scoring v1 | jq '.[].name' | grep -i "risk"`. Each command composes with every Unix tool.
|
|
68
|
+
- **Debuggability.** Human can run the exact same command the agent ran. MCP calls are opaque.
|
|
69
|
+
- **Token efficiency.** >10x more efficient than equivalent MCP tool definitions.
|
|
70
|
+
|
|
71
|
+
**When MCP makes sense:** non-developer access (analysts in chat UIs) or multi-agent runtime discovery.
|
|
72
|
+
|
|
73
|
+
**Three-layer stack:**
|
|
74
|
+
|
|
75
|
+
| Layer | Role | Example |
|
|
76
|
+
|---|---|---|
|
|
77
|
+
| **Capability (CLI)** | `--help` flags, JSON output, semantic exit codes | `tktl nodes describe credit-scoring v1 <id>` |
|
|
78
|
+
| **Procedure (Skill)** | How to use the CLI effectively: workflows, gotchas | `skills/flow-builder/SKILL.md` |
|
|
79
|
+
| **Bridge (MCP)** | 🔶 Thin wrapper calling CLI under the hood | Planned: `tktl-mcp-server` |
|
|
80
|
+
|
|
81
|
+
#### 1.3 Agent skills over vendor-specific commands
|
|
82
|
+
|
|
83
|
+
- Skills in `skills/` using [agentskills.io](https://agentskills.io) format, not `.claude/commands/`
|
|
84
|
+
- Vendor-neutral, works across 35+ agent products
|
|
85
|
+
- Each skill: `SKILL.md` + `references/` subfolder loaded on demand
|
|
86
|
+
|
|
87
|
+
#### 1.4 CLI resource ordering and structure
|
|
88
|
+
|
|
89
|
+
Pattern: `tktl <resource> <action>`. Consistent verbs across all resources.
|
|
90
|
+
|
|
91
|
+
| Resource | Read actions | Write actions |
|
|
92
|
+
|---|---|---|
|
|
93
|
+
| `flows` | `list`, `describe`, `explain`, `history` | `create`, `update`, `run`, `batch`, `wizard` |
|
|
94
|
+
| `versions` | `list`, `describe`, `diff`, `changes` | `create`, `duplicate`, `publish`, `archive` |
|
|
95
|
+
| `nodes` | `list`, `describe` | `add`, `edit`, `remove` |
|
|
96
|
+
| `update` | -- | `apply` (node config, params, schemas, full replace) |
|
|
97
|
+
| `groups` | `list`, `describe` | `create`, `update`, `delete`, `add-nodes`, `remove-nodes` |
|
|
98
|
+
| `datasets` | `list`, `describe`, `rows`, `download` | `create`, `upload`, `add-rows`, `update-row`, `delete-row`, `add-column`, `rename-column`, `delete-column`, `fill-column`, `sync-schema`, `delete` |
|
|
99
|
+
| `connections` | `list` | `create`, `create-resource`, `update-secrets` |
|
|
100
|
+
| `comments` | `list` | `add`, `delete` |
|
|
101
|
+
| `folders` | `list` | `create` |
|
|
102
|
+
| `auth` | `status` | `login`, `logout` |
|
|
103
|
+
| `config` | `get`, `list` | `set` |
|
|
104
|
+
| `cache` | `status` | `refresh`, `clear` |
|
|
105
|
+
| `render` | -- | *(top-level command)* |
|
|
106
|
+
|
|
107
|
+
**Read/write split enables agent permission models.** Coding agents auto-allow reads (`list`, `describe`, `diff`, etc.) and require approval for writes (`create`, `update`, `delete`, `run`, etc.). The verb convention makes this trivial to configure. New resources follow the same verbs, so the permission model covers them automatically.
|
|
108
|
+
|
|
109
|
+
#### 1.5 Configuration, authentication, and workspace routing
|
|
110
|
+
|
|
111
|
+
**Config** (`~/.tktl/config.json`): `org`, `workspace`, `env` (sandbox/live), optional URL overrides. Multiple environments via `TKTL_CONFIG_DIR`.
|
|
112
|
+
|
|
113
|
+
**Auth**: API key in `~/.tktl/credentials.json` (mode `0600`), attached as `X-Api-Key` header.
|
|
114
|
+
|
|
115
|
+
**Three API surfaces** 🔶 (to be consolidated):
|
|
116
|
+
|
|
117
|
+
| API | Used by |
|
|
118
|
+
|---|---|
|
|
119
|
+
| **Flow API** (`flow-api.taktile.com`) | All flow management: versions, nodes, groups, datasets, locks |
|
|
120
|
+
| **Taktile API** (`api.taktile.com`) | `auth login`, workspace management |
|
|
121
|
+
| **Workspace base URL** (per-workspace) | Flow execution (`flows run`, `flows batch`). Resolved from workspace object, cached. |
|
|
122
|
+
|
|
123
|
+
🔶 Plan: consolidate Flow API onto workspace base URL before public release.
|
|
124
|
+
|
|
125
|
+
### 2. CLI design
|
|
126
|
+
|
|
127
|
+
#### 2.1 Everything is JSON, pipes to jq
|
|
128
|
+
|
|
129
|
+
- Structured JSON to stdout, auto-detected (JSON for non-TTY, Rich tables for TTY)
|
|
130
|
+
- Errors to stderr as structured JSON with semantic exit codes (0-6, 10)
|
|
131
|
+
- Pipe to `jq`, `grep`, or any Unix tool
|
|
132
|
+
|
|
133
|
+
#### 2.2 Surgical reads and writes
|
|
134
|
+
|
|
135
|
+
- Targets the **smallest possible object** (single node, single parameter)
|
|
136
|
+
- `--full` for full document, `--summary` for one-liners, `--section` for single fields
|
|
137
|
+
- Large flows: `nodes list` returns ~3 lines per node, `nodes describe` returns ~30 lines for one node. Full-graph PATCH assembled by ops layer, invisible to caller.
|
|
138
|
+
|
|
139
|
+
#### 2.3 Human-readable identifiers
|
|
140
|
+
|
|
141
|
+
The original assumption was that human-readable names make the CLI more usable for both humans and agents. This holds for some resources but breaks on others.
|
|
142
|
+
|
|
143
|
+
- Flows by **slug**, versions by **name**: works well, both are unique
|
|
144
|
+
- Nodes, groups, datasets, connections, folders: by **UUID** (no guaranteed unique name)
|
|
145
|
+
|
|
146
|
+
🔶 **URL-to-identifier mismatch.** Platform URLs use UUIDs but CLI expects slugs/names. Agent must look up the mapping first. Needs to be addressed: accept UUIDs as alternative input, or add `tktl resolve <uuid>`.
|
|
147
|
+
|
|
148
|
+
#### 2.4 Cache-first with per-node decomposition
|
|
149
|
+
|
|
150
|
+
- One version fetch → decomposed into per-node files at `~/.tktl/cache/`
|
|
151
|
+
- Subsequent reads are local file reads, not API calls
|
|
152
|
+
- ETag-based conditional GETs (304 saves bandwidth)
|
|
153
|
+
- Writes invalidate only affected files
|
|
154
|
+
|
|
155
|
+
```
|
|
156
|
+
~/.tktl/cache/
|
|
157
|
+
├── index.json # slug→ID, name→ID
|
|
158
|
+
├── flows/{flow_id}/versions/{ver_id}/
|
|
159
|
+
│ ├── metadata.json # version meta + etag (no graph)
|
|
160
|
+
│ ├── full.json # backup for --full reads
|
|
161
|
+
│ └── nodes/
|
|
162
|
+
│ ├── _index.json # lightweight node list
|
|
163
|
+
│ └── {node_id}.json # individual node (~20-50 lines)
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
A 200-node flow: one API call, then all reads from cache.
|
|
167
|
+
|
|
168
|
+
#### 2.5 Optimistic concurrency via ETags
|
|
169
|
+
|
|
170
|
+
- PATCH/PUT sends `if-match: {etag}`. On 412: re-fetch → re-merge → resend (up to 3 retries)
|
|
171
|
+
- Node-level locks embedded in PATCH body. TTL-based expiry (300s). `--force` breaks locks.
|
|
172
|
+
- All invisible to the caller
|
|
173
|
+
|
|
174
|
+
#### 2.6 Batch execution with local results tracking
|
|
175
|
+
|
|
176
|
+
- `tktl flows batch`: 1-50 parallelism, max 1000 rows, CSV/JSON/JSONL or platform dataset
|
|
177
|
+
- Results as append-only JSONL in `~/.tktl/runs/{slug}/{run_id}/`
|
|
178
|
+
- `--query "output.data.decision"` for field extraction across rows
|
|
179
|
+
|
|
180
|
+
#### 2.7 Telemetry with PostHog
|
|
181
|
+
|
|
182
|
+
- Emitted from `tktl.ops`, tracked regardless of interface (CLI, library, MCP)
|
|
183
|
+
- Per-operation: `op`, `success`, `duration_ms`, `output_tokens`, `cache_hit`, `etag_retries`
|
|
184
|
+
- Opt-out via `tktl config set telemetry false`
|
|
185
|
+
|
|
186
|
+
### 3. Testing and tooling
|
|
187
|
+
|
|
188
|
+
#### 3.1 Toolchain
|
|
189
|
+
|
|
190
|
+
- **uv** (package manager), **ruff** (lint + format), **ty** (type checker), **hatchling** (build)
|
|
191
|
+
- Pre-commit hook: `ruff check` → `ruff format --check` → `ty check --error-on-warning`
|
|
192
|
+
- CI: lint → unit tests (fake API) → integration tests (real dev, main-only)
|
|
193
|
+
|
|
194
|
+
#### 3.2 Fake API server
|
|
195
|
+
|
|
196
|
+
Unit tests run against a Starlette ASGI app (`tests/fake_api/`) with in-memory state, wired via `httpx.ASGITransport`. No network calls, full HTTP semantics enforced:
|
|
197
|
+
|
|
198
|
+
| Rule | Behavior |
|
|
199
|
+
|---|---|
|
|
200
|
+
| ETag mismatch | 412 Precondition Failed |
|
|
201
|
+
| ETag match on GET | 304 Not Modified |
|
|
202
|
+
| Lock conflict | 409 Conflict |
|
|
203
|
+
| Merge patch | RFC 7396 (null deletes, nested recursion) |
|
|
204
|
+
| Missing resources | 404 |
|
|
205
|
+
|
|
206
|
+
Why fake server, not mocks: exercises the full stack (CLI → ops → api → HTTP → server), tests concurrency logic against real behavior, deterministic seed data.
|
|
207
|
+
|
|
208
|
+
#### 3.3 Integration tests against dev
|
|
209
|
+
|
|
210
|
+
Integration tests hit the real Taktile dev environment with real HTTP calls.
|
|
211
|
+
|
|
212
|
+
Why: the fake server can't catch API behavior changes, undocumented edge cases, or response format drift. Only way to verify the generated API client works against the real server.
|
|
213
|
+
|
|
214
|
+
What: flow listing, version PATCH with ETag negotiation, full build-and-run cycle (duplicate → add nodes → set schemas → execute → verify). Test versions cleaned up in fixture teardown.
|
|
215
|
+
|
|
216
|
+
Gating: requires `TKTL_DEV_API_KEY`, `@pytest.mark.integration`, CI runs only on push to `main`, uses a dedicated safe flow (`no-op-2`).
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## Consequences
|
|
221
|
+
|
|
222
|
+
### Expected Cost Impact
|
|
223
|
+
|
|
224
|
+
- **API calls:** cache decomposition = 1 fetch per version, not per node. 200-node flow: 1 API call instead of 200.
|
|
225
|
+
- **Tokens:** `nodes list` on 200-node flow: ~600 lines vs 10,000+ for full graph. Single `nodes describe`: ~30 lines.
|
|
226
|
+
- **Bandwidth:** conditional GETs return 304 for unchanged versions.
|
|
227
|
+
- 🔶 **To measure:** actual token usage per session, cache hit rates, API calls per agent task.
|
|
228
|
+
|
|
229
|
+
### Positive Consequences
|
|
230
|
+
|
|
231
|
+
- **Large flows work.** Cache decomposition + surgical reads make a 1000-node flow as easy to navigate as a 5-node flow.
|
|
232
|
+
- **Local tooling works.** JSON output → `jq`, `grep`, `diff` all work. Cache is a file tree. 🔶 Needs alternative for on-platform agents.
|
|
233
|
+
- **One ops layer, many interfaces.** CLI, Python import, MCP, on-platform copilot. No duplication.
|
|
234
|
+
- **Concurrent editing is safe.** ETag retries + node locks, transparent to caller.
|
|
235
|
+
- **API client stays in sync.** Generated from OpenAPI spec. Spec change = regenerate + test.
|
|
236
|
+
- **Fast tests.** Fake server enforces real HTTP semantics without network. Suite runs in seconds.
|
|
237
|
+
|
|
238
|
+
### Negative Consequences
|
|
239
|
+
|
|
240
|
+
- **First fetch is expensive.** Cold start for 1000-node flow = 10,000+ line response. Subsequent reads are cheap.
|
|
241
|
+
- **Full-graph PATCH complexity.** API requires all nodes in body. Ops layer hides this but implementation is non-trivial.
|
|
242
|
+
- 🔶 **Two API surfaces.** Different base URLs for management vs execution. Will be unified.
|
|
243
|
+
- **Generated code in repo.** Spec updates produce large diffs. Reviewers learn to ignore `tktl.generated/`.
|
|
244
|
+
- **Cache staleness.** 5-minute TTL, acceptable when agent owns the version.
|
|
245
|
+
- 🔶 **Node ID ergonomics.** UUID-only addressing. Revisit if name uniqueness can be enforced.
|
|
246
|
+
- 🔶 **Local tooling dependency.** `jq`, `grep`, filesystem access assumed. Risk for on-platform runtime (Q3'26). Ops layer Python import mitigates partially.
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# Agent Instructions
|
|
2
|
+
|
|
3
|
+
You are implementing the `tktl` CLI. Follow these files:
|
|
4
|
+
|
|
5
|
+
## Project Documentation
|
|
6
|
+
|
|
7
|
+
| File | Purpose |
|
|
8
|
+
|:---|:---|
|
|
9
|
+
| `docs/specs/core-implementation.md` | Full technical spec — source of truth for all behaviour, data models, API mappings, architecture. |
|
|
10
|
+
| `docs/specs/batch-run.md` | Batch run spec — multi-row execution, file formats, results storage, history, query extraction. |
|
|
11
|
+
| `docs/specs/posthog-instrumentation.md` | PostHog telemetry spec — event types, byte tracking, privacy. |
|
|
12
|
+
| `docs/plans/` | Implementation plans with checkbox task lists. Read before starting work. |
|
|
13
|
+
| `skills/` | Agent skills in [agentskills.io](https://agentskills.io) format. |
|
|
14
|
+
| `README.md` | Project overview and usage examples. |
|
|
15
|
+
| `src/tktl/openapi/flow-api-openapi.json` | OpenAPI spec for the Taktile Flow API. |
|
|
16
|
+
| `src/tktl/openapi/taktile-api-openapi.json` | OpenAPI spec for the Taktile API (auth, login). |
|
|
17
|
+
| `src/tktl/openapi/workspace-datasets-openapi.json` | OpenAPI spec for the Workspace Datasets API. |
|
|
18
|
+
| `src/tktl/openapi/workspace-dataset-jobs-openapi.json` | OpenAPI spec for the Workspace Dataset Jobs API. |
|
|
19
|
+
| `.env.example` | Environment variables for local integration testing. |
|
|
20
|
+
|
|
21
|
+
When working on a new feature, check `docs/specs/` for an existing spec first. If none exists, write one before implementing.
|
|
22
|
+
|
|
23
|
+
## Plans
|
|
24
|
+
|
|
25
|
+
Plans live in `docs/plans/` as simple markdown files with checkbox task lists. They track
|
|
26
|
+
implementation progress for a spec or ticket. A plan is the agent's working state —
|
|
27
|
+
read it first to build context, update it as you go.
|
|
28
|
+
|
|
29
|
+
**Format:**
|
|
30
|
+
|
|
31
|
+
```markdown
|
|
32
|
+
# Plan: <Title>
|
|
33
|
+
|
|
34
|
+
**Spec:** `docs/specs/<name>.md`
|
|
35
|
+
**Ticket:** [TICKET-ID](url)
|
|
36
|
+
|
|
37
|
+
## Tasks
|
|
38
|
+
|
|
39
|
+
- [x] Completed task
|
|
40
|
+
- [ ] Open task
|
|
41
|
+
- [ ] Another open task
|
|
42
|
+
|
|
43
|
+
## Blocked
|
|
44
|
+
|
|
45
|
+
- [ ] Decision needed: <question>
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
**Rules:**
|
|
49
|
+
- One plan per spec or ticket. Name it `plan-<topic>.md`.
|
|
50
|
+
- Use `- [ ]` for open, `- [x]` for done. Nothing else.
|
|
51
|
+
- Blocked items go under `## Blocked` — skip them and work on unblocked tasks.
|
|
52
|
+
- When you discover new work, add it to the task list.
|
|
53
|
+
- Prefix done plans with `done-` (e.g., `done-plan-core-initial.md`).
|
|
54
|
+
|
|
55
|
+
## Execution Loop
|
|
56
|
+
|
|
57
|
+
1. Find the relevant spec in `docs/specs/` and the plan in `docs/plans/` (if one exists).
|
|
58
|
+
2. If the task is blocked (needs human input), move it to **Blocked** in the plan, then skip to the next unblocked task.
|
|
59
|
+
3. If you discover new work, add it to the **Tasks** section in the plan.
|
|
60
|
+
4. Execute following TDD: write the test first, watch it fail, implement, watch it pass.
|
|
61
|
+
5. After each task: run `uv run pytest`, `uv run ruff check .`, `uv run ruff format .`. Fix any failures before moving on.
|
|
62
|
+
6. Run `uv run ty check src/ tests/` — all code must pass strict type checking.
|
|
63
|
+
7. Check off the task in the plan (`- [x]`).
|
|
64
|
+
8. Commit after each completed phase.
|
|
65
|
+
9. Go to step 1. **Do not stop until every task is checked off.**
|
|
66
|
+
|
|
67
|
+
## Key Constraints
|
|
68
|
+
|
|
69
|
+
- **Library-first**: all logic lives in `src/tktl/ops/`. CLI commands are thin wrappers.
|
|
70
|
+
- **Test-driven**: never write implementation before writing the failing test.
|
|
71
|
+
- **Astral-only tooling**: use `uv`, `ruff`, `ty`. No pip, no mypy, no black.
|
|
72
|
+
- **Fake API for unit tests**: unit tests run against the fake server in `tests/fake_api/`.
|
|
73
|
+
- **Real API for integration tests**: integration tests in `tests/test_integration/` hit the real Taktile dev environment. They require `TKTL_DEV_API_KEY` in `.env`.
|
|
74
|
+
- **No hallucinated endpoints**: the Flow API has no node-level endpoints. Nodes are extracted client-side from the version graph. Check `docs/specs/core-implementation.md` Appendix A for the exact endpoints.
|
|
75
|
+
- **Session header required**: PATCH requests that modify rule_2, split_2, or assignment_node metas require a `session` header.
|
|
76
|
+
- **Full nodes in PATCH**: the API requires ALL nodes in the graph patch body, not just the modified one. Sending only the target node causes 409 "graph not fully connected".
|
|
77
|
+
- **Pre-commit hook**: runs ruff check + ruff format + ty check. Install via `uv run python scripts/install-hooks.py`.
|
|
78
|
+
|
|
79
|
+
## Agent Behaviour (always active)
|
|
80
|
+
|
|
81
|
+
1. **Clarify before implementing — but use Chrome first for context only.**
|
|
82
|
+
- **Always use the CLI to retrieve flow, version, and node data.** When you need to describe, inspect, or reason about flow logic, schemas, node configuration, or graph structure, use `tktl versions describe`, `tktl nodes list`, `tktl nodes describe`, etc. Never scrape the browser UI to read flow logic — the CLI returns the complete, structured data.
|
|
83
|
+
- Chrome is for **context resolution only**: parse the URL to extract org_id, workspace_id, flow_id, version_id, and node_id. Then pass those identifiers to the CLI. **Do NOT run `tktl config list` or other CLI config commands to find out what's active when Chrome is open.**
|
|
84
|
+
- If Chrome tools are absent: use `tktl config list` to resolve workspace/org, and list open factual AND logic questions before writing any API calls.
|
|
85
|
+
- Only ask the user about things neither the CLI nor Chrome can tell you: undecided business logic, thresholds not yet defined, ambiguous requirements.
|
|
86
|
+
- Never guess at connection names, node IDs, or field values.
|
|
87
|
+
|
|
88
|
+
2. **Render before building.** Always run `tktl render --text "..."` with a complete Mermaid diagram and get user approval before any `tktl versions duplicate` or `tktl nodes add` calls.
|
|
89
|
+
|
|
90
|
+
3. **Schema first.** Every flow must have explicit input and output schemas. Define them before (or immediately after) creating the version — before adding any logic nodes. For every field the flow reads from `data.*`, declare it in `--schema-in`. For every field the flow writes to `data.*` that the caller will consume, declare it in `--schema-out`. Without schemas: `data: {}` is returned and batch runs can't be queried by field. Apply with:
|
|
91
|
+
```bash
|
|
92
|
+
tktl update apply <slug> <ver> --schema-in @input_schema.json --schema-out @output_schema.json
|
|
93
|
+
```
|
|
94
|
+
Include schema design in the Mermaid brainstorm step — label the I/O nodes with the actual field names.
|
|
95
|
+
|
|
96
|
+
4. **Chrome tools — read and show only. NEVER edit via Chrome.**
|
|
97
|
+
All flow edits go through the CLI. Chrome MCP tools have exactly two permitted uses:
|
|
98
|
+
- **Inspect** — read the current state to orient yourself (e.g. what workspace/flow/node is open, what a node's config looks like). Use this to answer your own questions before asking the user.
|
|
99
|
+
- **Navigate to show the user** — open a URL so the user can see something (a flow, a node pane, a Mermaid PNG preview). Only navigate; do not interact further.
|
|
100
|
+
|
|
101
|
+
When Chrome tools are present:
|
|
102
|
+
- After rendering a Mermaid PNG → use `Bash: open {png_path}` (macOS) to open the PNG in Preview. Do NOT use Chrome navigate for `file://` paths — Chrome MCP prepends `https://` and mangles them.
|
|
103
|
+
- After creating or duplicating a version → navigate Chrome to the Taktile flow URL.
|
|
104
|
+
- When asked to show a node → navigate to `?node={node_id}&right-pane-tab=logic`. If the node_id is unknown, use `tktl nodes list <slug> <version>` to look it up — never use JavaScript or click the canvas.
|
|
105
|
+
- Build Taktile URLs via `from tktl.config import Config, derive_app_url` + `from tktl.ops.render import build_flow_url`. The `org_id` is auto-fetched and cached by `build_deps()`.
|
|
106
|
+
- URL pattern: `/flow/{flow_id}/version/{version_id}` — always singular `flow`, always include version. Never `/flows/`, never omit the version.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Claude Code Instructions
|
|
2
|
+
|
|
3
|
+
Read and follow `AGENTS.md` for all implementation guidance.
|
|
4
|
+
|
|
5
|
+
## Reference Docs
|
|
6
|
+
|
|
7
|
+
| File | Purpose |
|
|
8
|
+
|:---|:---|
|
|
9
|
+
| `skills/flow-builder/references/node-configs.md` | Per-type node config examples and gotchas |
|
|
10
|
+
| `skills/flow-builder/references/flow-patterns.md` | Node sequence patterns by use case |
|
|
11
|
+
| `skills/flow-builder/references/debugging.md` | Debugging procedures for flow issues |
|
|
12
|
+
| `skills/flow-builder/references/executing-flows-and-local-testing.md` | Running flows, async mode, mocking, integration test patterns |
|
|
13
|
+
| `skills/flow-builder/references/working-with-child-flows-and-loop-nodes.md` | Child flows, subflow mocking via `mock_data`, cross-workspace promotion |
|
|
14
|
+
|
|
15
|
+
## Rendering Flows
|
|
16
|
+
|
|
17
|
+
When asked to render/visualize/diagram a flow, always:
|
|
18
|
+
1. Use the CLI: `uv run tktl versions describe <slug> <version> --preview`
|
|
19
|
+
2. Open the resulting PNG in Preview: `open <path>`
|
|
20
|
+
|
|
21
|
+
Do not generate raw Mermaid text in the conversation.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: tktl-cli
|
|
3
|
+
Version: 0.1.0a1
|
|
4
|
+
Summary: A developer- and agent-friendly CLI for managing Taktile decision flows.
|
|
5
|
+
Requires-Python: >=3.11
|
|
6
|
+
Requires-Dist: graphviz>=0.21
|
|
7
|
+
Requires-Dist: httpx>=0.28
|
|
8
|
+
Requires-Dist: posthog>=7.0
|
|
9
|
+
Requires-Dist: pydantic>=2.12
|
|
10
|
+
Requires-Dist: rich>=14.0
|
|
11
|
+
Requires-Dist: typer>=0.24
|