Repository navigation
Expand file tree
/
Copy pathsetup.cfg
More file actions
815 lines (803 loc) · 48.7 KB
/
Copy pathsetup.cfg
File metadata and controls
815 lines (803 loc) · 48.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
[options]
zip_safe = True
include_package_data = True
# macOS (x86_64 + arm64), Linux (x86_64 + aarch64), and Windows, CPython
# 3.12-3.13. Declaring this gives pip a clear, early error on an unsupported
# interpreter instead of a late syntax/dependency failure.
#
# Must match pyproject.toml's requires-python: that [project] value is the one
# that actually lands in the built metadata, so a looser bound here is dead
# config that misleads readers into thinking 3.10/3.11 is supported (they are
# not — every release artifact bundles CPython 3.12, ensure-python.sh
# provisions 3.12, and 3.12 is the only version CI tests).
python_requires = >=3.12
package_dir =
= src
packages = find:
install_requires =
aiohttp>=3.9,<4
# The decision provider client (decisions/impl_systemone.py): one persistent
# HTTP/2 connection per loop carries every decision in flight as its own
# stream. Pinned: the transport of every decision request.
httpx[http2]==0.28.1
# Security.framework-backed TLS validation for bundled macOS Python.
# File CA bundles cannot preserve Keychain trust policy or explicit deny.
truststore==0.10.4; sys_platform == "darwin"
# Direct dependency, not just aiohttp's transitive one: the link-unfurl vet
# derives the resolver-pin host with `yarl.URL.raw_host` so it matches the
# exact key aiohttp asks its resolver with. Pinning on any other encoding of
# the host silently refuses every internationalized domain.
yarl>=1.9,<2
# Direct dependency, not just aiohttp's transitive one: the channel wire
# harness answers canned responses through aiohttp's own reader methods,
# which look headers up by aiohttp's spelling. Only multidict's
# CIMultiDict matches a fixture header case-insensitively the way a real
# response does; a plain dict makes `content-type` and `Content-Type` two
# fields and lets a canned body read as JSON that production refuses.
multidict>=6.0,<7
slack-sdk>=3.27,<4
websockets>=12,<16
cron-descriptor>=1.4,<2
croniter>=2.0,<3
# Direct dependency, not just a transitive one (black/mypy pull it in):
# the project scanner honors .gitignore when detecting packages, and
# pathspec's GitIgnoreSpec is the maintained implementation of gitignore
# matching semantics (negation, dir-only patterns, last-match-wins).
pathspec>=0.12
# Config validation runs on every installed gateway, not only in a source
# checkout with dev extras. Without this dependency the optional import in
# config.validation silently skips schema checks on malformed config.
jsonschema>=4.26,<5
# The Markdown session export (dashboard/session_markdown.py) closes a turn's
# unterminated fence or HTML block at the message boundary so later turns stay
# readable, and it decides what is open by PARSING each message with this
# CommonMark reference implementation rather than with a hand-written scanner
# -- every review of the scanner found another container rule it got wrong.
# Pure Python, one pure-Python transitive dependency (mdurl), already pinned
# by the decision local servers' requirements. Installed gateways render the
# export, so it is a runtime dependency and not a dev one.
markdown-it-py>=3,<5
numpy>=1.21,<3
# Session search splits a Chinese query into dictionary words (history_words).
# rjieba is the jieba-rs binding: MIT, abi3 wheels for Linux x86_64/aarch64,
# macOS x86_64/arm64 and Windows x64/x86 (jieba itself ships only an sdist,
# which --only-binary=:all: refuses). 0.2.1 has no Windows ARM64 wheel, so it
# is skipped there rather than built from source: search falls back to the
# character path without it, exactly as on any host where the import fails.
# Loaded once, lazily, in the gateway. Pinned: a dictionary change re-splits
# every query.
rjieba==0.2.1; sys_platform != "win32" or platform_machine != "ARM64"
snowballstemmer>=1.0
# stdlib zoneinfo reads the system IANA tz database and falls back to the
# tzdata package where there is none: Windows always, and Linux hosts
# without the OS tzdata package (stock ubuntu/debian container images, slim
# servers). With neither, ZoneInfo() raises ZoneInfoNotFoundError for every
# zone, UTC included, so this applies on every platform. A system tree
# still wins where one exists. The floor is the first release carrying IANA
# tzdb 2026b, which keeps America/Vancouver on UTC-7 all year; older data
# runs jobs in that zone an hour late every winter.
tzdata>=2026.2
# Windows web-terminal backend: the dashboard terminal uses a ConPTY
# pseudo-console, and pywinpty is the maintained ConPTY binding. Windows
# only — POSIX drives the terminal with the stdlib pty/fork instead.
pywinpty>=2.0,<4; platform_system == "Windows"
# Windows keeps its timezone in the registry as a Windows zone id
# ("Pacific Standard Time"); tzlocal maps it to IANA via the CLDR
# windowsZones table so timezone auto-detection works and the product does
# not silently fall back to UTC. POSIX reads $TZ / /etc/localtime directly.
# Its only dependency, tzdata, is already declared above.
tzlocal>=5.0; platform_system == "Windows"
# Vendored llama-cpp-python runtime imports (in-process embeddings).
jinja2>=2.11.3
typing-extensions>=4.5.0
# Dashboard file viewer xlsx preview (GET /api/file-sheet): parses OOXML
# workbooks into a JSON cell grid with openpyxl. openpyxl switches its XML
# parsing to defusedxml (declared below for doc_parser) whenever that
# module is importable, which hardens the endpoint against XML
# entity-expansion payloads inside untrusted workbook files.
openpyxl>=3.1,<4
# pysqlite3 needed on older Linux x86_64 (old SQLite lacks FTS5/UPSERT);
# modern Linux, macOS, and aarch64 ship a recent SQLite. No aarch64 wheels exist.
pysqlite3-binary>=0.5.4; sys_platform == "linux" and platform_machine == "x86_64"
# docx ingestion. 0.8.x ships `from collections import Sequence` (removed in
# Python 3.10), an ImportError at runtime — require 1.x, which fixes the
# import and is API-compatible for our usage (Document(), paragraphs, style).
python-docx>=1,<2
pdfplumber>=0.10,<1
# doc_parser parses the XML inside user-supplied .docx/.pptx uploads. The
# stdlib xml.etree parser resolves external entities, so a crafted document
# can mount an XXE (local-file read / entity-expansion DoS). defusedxml is a
# pure-Python, dependency-free drop-in that hardens fromstring() against it.
defusedxml>=0.7,<1
# WeChat (weixin) QR login: iLink returns a scannable login URL, not image
# bytes — the dashboard renders it into a PNG server-side. qrcode[pil]
# pulls Pillow explicitly (we already ship it transitively via pdfplumber,
# but the QR path must not depend on another feature's dependency tree).
qrcode[pil]>=7.4,<9
# WeChat (weixin) inbound media: iLink never carries bytes in the envelope,
# it hands out a CDN reference whose object is AES-128-ECB encrypted, so
# reading an inbound image/voice/file requires a real AES implementation.
# Declared in core (not an extra) for the same reason as qrcode above: the
# weixin channel ships enabled-by-config, and a channel must not depend on
# another feature's dependency tree to receive a message.
cryptography>=42,<48
requests>=2.28,<3
# Agent frontmatter parsing, eval scenario specs, and the task planner.
PyYAML>=6,<7
# Telemetry trunk (Wave 0): OpenTelemetry SDK metrics. Apache-2.0 / CNCF
# standard. The local JSONL sink is the default; OTLP egress is available
# through the explicit kirocrew[otlp] package extra. Consumed by src/kiro_crew/metrics/.
opentelemetry-api>=1,<2
opentelemetry-sdk>=1,<2
# PPTX Maker provisions its presentation engine into a uv-managed venv. Ships
# the uv binary as a wheel (MIT OR Apache-2.0), located via uv.find_uv_bin(),
# so a stock `pip install kirocrew` can provision the engine with no separate
# `brew`/`curl` step. Not a build backend — see apps/builtins/pptx_maker.
# Floor is 0.6.7 because pod provisioning (pod/provision.py::_ensure_venv_uv)
# runs `uv pip install --group dev`, and `--group` on `uv pip install` first
# shipped in uv 0.6.7 (uv changelog 0.6.x); an older uv would exit nonzero
# and silently fall back to pip on every provision. The other flags that
# path uses are older than the floor: `uv venv --allow-existing` (0.1.40),
# `uv venv --seed` (0.1.x) and `--link-mode` honoured for `uv venv` seed
# packages (0.1.32).
uv>=0.6.7,<1
[options.extras_require]
# HOW TO INSTALL ONE OF THESE. `pip install "kirocrew[<extra>]"` does NOT work:
# this project is not published on any index, so pip fails with "No matching
# distribution found for kirocrew" regardless of how Kiro Crew was installed --
# and were it published, that form would REPLACE an editable/source install with
# a released wheel. Install an extra's own distributions instead (the commands
# below), or from a source checkout use `pip install -e ".[<extra>]"`. At runtime
# `kiro_crew.extras` renders these lists for the dashboard and the logs, so a pin
# changed here reaches the user's copy button without a code change.
# Optional OTLP/HTTP metrics egress. Network export still requires an explicit
# telemetry.otlp_endpoint; installing this extra alone does not enable egress:
# pip install "opentelemetry-exporter-otlp-proto-http==1.44.0"
otlp =
opentelemetry-exporter-otlp-proto-http==1.44.0
# Optional out-of-process profiling for `kirocrew perf sample --pid`. The
# in-process sampler (`--call`) needs nothing extra; py-spy is only required to
# attach to an already-running gateway, and on macOS also needs elevated
# privileges (task_for_pid). Profiling stays off unless KIROCREW_DEBUG is set:
# pip install 'py-spy>=0.3,<1'
perf =
py-spy>=0.3,<1
# Optional Microsoft Teams channel. The inbound Bot Framework webhook validates
# an RS256 JWT (issuer + App-ID audience + JWKS signature) before processing, so
# it needs PyJWT + cryptography. Install with:
# pip install "PyJWT[crypto]==2.15.0"
teams =
PyJWT[crypto]==2.15.0
# Optional WhatsApp channel (QR-linked personal account over the WhatsApp Web
# protocol). neonize bundles the Go whatsmeow core as a prebuilt shared
# library; core kirocrew runs without it and the channel reports the missing
# extra in Settings. Install with:
# pip install 'neonize==0.4.3.post0'
whatsapp =
neonize==0.4.3.post0
# Optional Feishu (Lark/飞书) channel. Unlike the other non-Slack channels, the
# Feishu long-connection transport is not a plain HTTP/WS endpoint we can drive
# with aiohttp: the handshake, tenant-token refresh and frame envelope are only
# specified through the official SDK, so the channel depends on lark-oapi. It
# stays OUT of core (same reasoning as [teams]) and is lazily imported, so a
# build without it simply logs and skips the channel. Install with:
# pip install 'lark-oapi>=1.4,<2'
feishu =
lark-oapi>=1.4,<2
# Optional Amazon Bedrock Knowledge Base retrieval source (knowledge sources
# of type bedrock_kb). Queries an existing KB in the user's own AWS account
# live at search time; core kirocrew runs without it and the source type
# reports the missing extra on add. Same boto3 pin as [voice-aws] so the two
# extras can never demand incompatible cores. Install with:
# pip install 'boto3>=1.34,<2'
bedrock =
boto3>=1.34,<2
# Optional speech-to-text integration. Install with:
# pip install 'boto3>=1.34,<2' 'amazon-transcribe>=0.6.3,<1' 'pywhispercpp>=1.5,<2'
# pywhispercpp is the whisper.cpp binding (MIT) behind the default `local`
# provider, held loaded in-process by kiro_crew.stt. Desktop releases bundle this
# binding and its runtime dependencies; users only download their selected model.
# Prebuilt wheels cover macOS arm64, glibc and musl Linux on x86_64 and aarch64,
# and Windows. Intel macOS has NO wheel, so pip builds it from source there and
# needs a C++ toolchain plus CMake; kiro_crew.stt.engine reports that as its own
# availability state rather than as a missing extra, because the two need
# different fixes.
# amazon-transcribe (and its boto3 credential resolver in kiro_crew.transcribe)
# is only needed for the `transcribe` (AWS) provider. Desktop packaging adds its
# pinned imageio-ffmpeg decoder separately; source environments deliberately use
# a system decoder instead of executing a binary from an agent-writable venv.
# Core kirocrew runs without these extras and reports STT as unavailable precisely.
# The cloud half, split out so a platform with no recogniser wheel can still get
# it. An extra resolves ATOMICALLY, so with the full `voice` set on Intel macOS --
# where pywhispercpp publishes no wheel -- the whole install fails and boto3 and
# amazon-transcribe are omitted with it, taking the `transcribe` provider down
# alongside the `local` one it has nothing to do with. Packaging installs this
# first, then attempts the recogniser separately.
voice-aws =
boto3>=1.34,<2
amazon-transcribe>=0.6.3,<1
voice =
kirocrew[voice-aws]
pywhispercpp>=1.5,<2
# Development and test tooling:
# pip install -e ".[dev]"
# Keep in sync with [dependency-groups] dev in pyproject.toml, which CI
# installs via `--group dev`; this extra is what `make build` uses.
# The formatter/linter/type-checker are pinned to the exact versions CI runs:
# black and mypy change their output across minor releases, so a floating range
# makes a local `make build` venv disagree with CI (black 26 reformats ~680
# files that black 24 accepts). Bump these in lockstep with pyproject.toml.
dev =
# The version CI installs: `strict_markers` below is a pytest 9 ini key.
pytest==9.0.3
pytest-cov>=4,<7
# The three plugins that decide a test's event loop, worker and timeout are
# pinned to CI's versions: a newer pytest-asyncio drops the implicit
# event_loop fixture the conftest floor joins executor jobs through.
pytest-asyncio==0.21.2
pytest-xdist==3.5.0
pytest-timeout==2.2.0
pytest-testmon>=2
# Imported unconditionally by test/conftest.py.
hypothesis>=6
black==26.10.1
isort==6.0.0
flake8==7.1.0
mypy==1.14.1
# Not a dev TOOL -- see the [dependency-groups] dev rationale in
# pyproject.toml: kiro_crew.config.validation imports jsonschema behind a
# try/except, so a `.[dev]` install without it silently SKIPS the 11
# config-validation guard tests (pytest scores a skip as a pass). Keep the
# pin identical to the group's.
jsonschema==4.26.0
PyJWT[crypto]==2.15.0
# Test-only, NOT a runtime dependency -- see the [dependency-groups] dev
# rationale in pyproject.toml (kept in lockstep with it). test_transcribe_ffmpeg.py's
# pin-completeness test imports imageio_ffmpeg._definitions.FNAME_PER_PLATFORM
# to derive the authoritative bundled-decoder filename set; without the package
# the test would importorskip and silently pass, which is the "green while
# checking nothing" shape that test exists to end. imageio_ffmpeg stays a
# packaging and runtime concern for the desktop bundle, NOT a core
# install_requires.
imageio-ffmpeg==0.6.0
[options.packages.find]
where = src
exclude =
test
[options.package_data]
kiro_crew =
py.typed
# The AWS Control crew container image's build context: the Dockerfiles, the
# container's own source and requirements, its CONTRACT.md and the vendor
# placeholder. Each is read FROM DISK when the image is built, and `crew/` is not
# one of the fixed directory names below -- `*` does not cross a path separator, so
# an `apps/builtins/*/runtime/**/*` entry would not reach
# `aws_control/crew/runtime/`. Without these lines the tree works from a source
# checkout and is absent from every pip and DMG install, with nothing raising.
#
# Four entries naming what the image needs, rather than one `runtime/**/*` that
# takes the whole tree. The broad glob also shipped `container_tests/` -- a 4,000
# line suite of the image's own tests -- to every user's wheel and DMG, where
# nothing can run it: the tests exercise a Linux container's supervisor, and the
# machine that installed the app never runs that container. An allowlist cannot
# acquire a new subtree by accident, which is why this is not the broad pattern
# plus an `exclude_package_data` line.
apps/builtins/*/crew/runtime/Dockerfile*
# The guest's SSM agent configuration, read FROM DISK when the MicroVM recipe
# is assembled. Named on its own because no glob above reaches a .json at the
# runtime root.
apps/builtins/*/crew/runtime/microvm-ssm-agent.json
apps/builtins/*/crew/runtime/.dockerignore
apps/builtins/*/crew/runtime/container/**/*
# The placeholder ONLY, named exactly, so the directory exists in an installed
# copy and a missing wheel is reported as a missing wheel rather than a missing
# directory. Emphatically not `vendor/*`: a wheel is STAGED into this directory
# to build a MicroVM image, and a pattern that reaches it packages that wheel
# inside the next one. One staged wheel adds ~36 MB and puts the following
# build past the 64 MiB recipe ceiling, so the second image build on a machine
# refuses. `test_crew_runtime_payload.py` holds both lanes to it.
apps/builtins/*/crew/runtime/vendor/.gitkeep
# Optional distribution build stamp (kiro_crew/__init__.py). Absent in this
# repo and in the wheels it publishes; a downstream that writes it before
# building its own wheel needs it carried into the package.
BUILD_VERSION
slack-manifest.yaml
model_registry.json
# Every crewmate prompt piece (crewmate_prompts.py reads it at import).
crewmate_prompts.json
connections/registry.json
data/tips_catalog.json
data/mcp_tool_titles.json
data/discovery_featured.json
# Swift source for the Apple on-device speech helper. Shipped as SOURCE, not a
# binary: a prebuilt Mach-O would need signing/notarization to clear Gatekeeper
# on a downloaded DMG, so kiro_crew.apple_speech compiles it on the host once.
# Without this entry the `apple` STT provider silently reports unavailable on
# every pip/DMG install while working perfectly from a source checkout.
apple_speech/*.swift
# The hash-pinned requirement set the Browser Harness installer feeds to
# ``pip install --require-hashes`` (browser_harness/install.py). Without this
# entry every pip/DMG install reports the lock file missing and refuses to
# install the browser engine, while a source checkout works. Regenerate with
# ``uv pip compile --generate-hashes --universal`` when HARNESS_VERSION moves.
browser_harness/requirements.lock
# Crew webview templates. Same failure shape as the Swift helper above, and
# the reason it is called out again here: without this entry `resolve_template`
# finds neither an override nor a shipped template on any pip/PyPI/DMG install,
# so EVERY `panel_publish` returns 400 `unknown_template` while the feature
# works perfectly from a source checkout -- because the tests and a dev run
# both read the package-relative source tree. A test asserts this glob covers
# the shipped directory so the next template cannot regress it.
agent_panel_templates/*.html
# Derived-card pages (e.g. the pipeline board). Kept out of dashboard_templates on
# purpose: that is the TemplateSpec registry package, whose gate requires every page
# there to carry a registry row, and this card uses a different provider/contract shape.
# Same silent failure mode as the entries above -- a page absent from the wheel ships
# its provider and contract working while the card renders nothing. A test asserts the
# glob covers the shipped directory.
dashboard_card_pages/*.html
# Dashboard-template pages. Added with the machinery rather than with the first
# template, because the failure mode is silent in exactly the same way as the
# entry above: a page absent from the wheel leaves its provider and its contract
# shipped and working, so every gate stays green while the card renders nothing on
# any pip/PyPI/DMG install. A test asserts the glob covers the shipped directory.
dashboard_templates/*.html
# Built-in dynamic-dashboard templates, one directory per template. BOTH files are
# listed and the manifest is the reason this entry is not optional: the html happens
# to be matched by the glob above under setuptools' own matching, but
# `manifest.json` is matched by nothing, and a template directory holding only a page
# is refused by `load_template` -- so the registry finds NO built-in on any
# pip/PyPI/DMG install while every gate here stays green, because the tests and a dev
# run both read the package-relative source tree. A test asserts a glob covers both
# file kinds so the next template cannot regress it.
dashboard_templates/builtin/*/*.html
dashboard_templates/builtin/*/*.json
dashboard_templates/builtin/*/helpers/*.py
# Local decision model launchers and their dependency locks. The gateway runs a
# launcher in the model's own environment and builds that environment from the
# lock, so both are read from disk at runtime; without this entry a pip or DMG
# install could offer a local model and never start it.
decisions/local_servers/*.py
decisions/local_servers/*.txt
config/defaults.json
config/prompt.md
# The `browser` tool's page-side walker, read from disk and evaluated in the
# agent's tab (browser_harness/ops.py). Without it every snapshot/click/type
# fails on a pip or DMG install while working from a source checkout.
browser_harness/snapshot_walker.js
cloud/templates/*.yaml
# The credential rule table, read through importlib.resources at first use.
security/redaction_rules/*.yaml
apps/app-registry.json
# The former built-in adoption pins (apps/builtin_adoption_pins.py).
apps/adoption-pins.json
apps/builtins/*/app.json
apps/builtins/*/ui/**/*
apps/builtins/*/lib/**/*
apps/builtins/*/backend/**/*
apps/builtins/*/agents/**/*
apps/builtins/*/inject/**/*
apps/builtins/*/skills/**/*
apps/builtins/*/scripts/**/*
apps/builtins/*/agents/*.json
apps/builtins/*/prompts/*.md
# ATTRIBUTION.md / README.md carry the upstream-author credit for the builtin
# apps ported from third-party work — Apache-2.0 attribution has to reach the
# installed package, not just the repository. This glob also subsumes the
# `README.md` line this branch had added separately.
apps/builtins/*/*.md
builtin_skills/**/*
# Gate extensions Kiro Crew loads INTO a harness that has no permission
# gate of its own (agent_sdk/backends_routing.py, Routing.VERIFIED_GATE_EXTENSION).
# Shipped as the harness's own extension language, read-only package data;
# the driver names the file on the harness's command line at spawn.
agent_sdk/gate_extensions/*/*.ts
agent_sdk/gate_extensions/*/*.mjs
agent_sdk/gate_extensions/*/*.py
deploy/skills/**/*
eval/scenarios/*.json
eval/bench/data/*.json
docs/*.md
# settings-registry.generated.json: the agent's enumeration of the dashboard
# Settings controls, generated by `npm run gen:settings` and read at runtime
# from the bundled docs dir, so it has to ship like the prose beside it.
docs/*.json
static/*
tests_fixtures/**/*
_vendor/**/*
# Vendored llama-cpp-python: Python source + per-platform native libs.
# The `_vendor/**/*` glob above relies on setuptools `**` recursion, which
# is unreliable across versions — keep these explicit entries too.
_vendor/llama_cpp/*.py
_vendor/llama_cpp/py.typed
_vendor/llama_cpp/LICENSE.md
_vendor/README.md
_vendor/llama_cpp_libs/linux_x86_64/*
_vendor/llama_cpp_libs/linux_aarch64/*
_vendor/llama_cpp_libs/linux_aarch64_dotprod/*
_vendor/llama_cpp_libs/macos_arm64/*
_vendor/llama_cpp_libs/macos_x86_64/*
_vendor/llama_cpp_libs/win_amd64/*
[options.entry_points]
# Console scripts installed onto PATH by pip:
# kirocrew -> kiro_crew._bootstrap:main (self-heals stale editable
# installs, then dispatches to kiro_crew.cli:main)
console_scripts =
kirocrew = kiro_crew._bootstrap:main
# Configuration for pytest; enable coverage for KiroCrew, emit
# XML, HTML, and terminal reports.
[tool:pytest]
xfail_strict = true
# A misspelt or unregistered mark is an error, not a warning: `@pytest.mark.timout(5)`
# would otherwise apply nothing and the test would run under the default timeout. Every
# mark in use is registered (below, or by its plugin); a full collection with
# `-W error::pytest.PytestUnknownMarkWarning` finds none unregistered. The ini key, not
# `--strict-markers` in addopts: pytest 9 reads ini overrides before it expands addopts,
# so the flag there changes nothing.
strict_markers = true
markers =
ipv6_required: requires native IPv6 loopback; CI routes these tests to hosted runners
real_venv: spawns a real ``python -m venv`` + pip child; excluded from the sharded Backend Tests lane and run by the wheel-engine-real-venv CI job instead
integration: live browser tests requiring Chrome CDP
real_adapter: drives a REAL installed adapter or harness. Skips where it is absent and FAILS instead under KIROCREW_E2E_REQUIRE=1; the "Real Adapter Contract Tests" lane selects on this marker, so a guarded test added later is included rather than left out of an enumerated list
real_builtin_skills_sync: keep SkillsLoader()'s real install_builtins=True default; the rootdir conftest otherwise defaults an OMITTED install_builtins to False so bare ContextBuilder()/SkillsLoader() calls skip the ~20s builtin-skills sync
keep_runtime_ownership_tables: leave runtime_ownership's lease and tenancy tables as earlier tests left them; test/conftest.py otherwise wipes both on each side of every test, which would make a positive control that reads the table pass vacuously
real_network: the test reaches a host other than loopback on purpose; the rootdir conftest's network floor neither reports it nor, under KIROCREW_NET_STRICT=1, refuses it
scale_budget: an operation- or byte-count budget over a seeded scale shape (test/scale_budget/); never a wall-clock limit
pythonpath = src
# Keep a test's tmp_path only when that test FAILED, which is the only case anyone
# ever reads it. The default ("all") keeps every passing test's directory too, and
# with tmp_path_retention_count also defaulting to 3 that retains the whole suite's
# temp footprint three times over -- at ~56.5k tests, on a /tmp that is a tmpfs with
# a fixed inode budget (1,048,576 on the hosts this was measured on), that is what
# eventually returns ENOSPC to unrelated processes while 90% of the BYTES are still
# free. Debuggability is unaffected: a failing test's directory is still kept, for
# the configured number of runs, which is the only one anybody opens.
tmp_path_retention_policy = failed
addopts =
--verbose
--ignore=build/private
# Refuse platformdirs' `pytest11` entry point. platformdirs ships a
# `platformdirs_isolated` fixture as an auto-loaded plugin, so pytest
# imports `platformdirs.pytest_plugin` during startup on every invocation,
# for every lane, whether or not anything asks for the fixture. Nothing in
# this repository does. A `pytest11` import that raises is fatal before
# collection, so when that import fails the shard exits 1 having run zero
# tests, and the annotation says only `exit code 1`.
#
# platformdirs is a transitive dependency -- black and pip-audit both
# require it. pyproject.toml's dev extra bounds it (`platformdirs<4.12`) for
# the nested pytest processes that suppress this config; this block covers
# every run that reads it, for any version that carries the entry point:
# pluggy tests the block BEFORE it imports the module, so an unimportable
# plugin cannot fail the run. It is also free -- the fixture is unused here.
-p no:platformdirs
# Parallel test execution via xdist. Override with -n0 for debugging:
# pytest -n0 -k test_name --pdb
#
# `auto` does NOT mean one worker per core here: the rootdir conftest's
# pytest_xdist_auto_num_workers hook bounds it by available memory and by
# what concurrent runs on this host already hold. A worker costs ~1.5 GiB,
# almost all of it collecting the suite, so a small laptop cannot back one
# per core -- see testing-conventions.md "Running on a machine with little
# RAM" for the knobs. An explicit -n <N> bypasses the budget.
-n auto
# loadgroup (not worksteal) so @pytest.mark.xdist_group is honored: the
# concurrency-sensitive tests marked xdist_group(name="serial") (transcribe,
# dashboard approval) run on one worker instead of racing under -n auto.
--dist loadgroup
# Fail fast instead of thrashing. When workers die from memory pressure
# xdist silently clones replacements, up to numprocesses*4 of them -- a
# 10-worker run will quietly restart 40 times, which on a host that has
# started swapping means ~20 minutes of zero progress and an empty log.
# Two replacements is enough to absorb a genuine one-off crash; past that
# the run is not going to finish, so surface it loudly and immediately.
--max-worker-restart=2
--timeout=120
# Coverage is NOT enabled by default: measured on a 1,231-test subset it
# costs +21% wall time (52.5s -> 63.4s) and +36% peak worker RSS (387MB ->
# 527MB) on every local and agent run, while CI asks for it explicitly
# (ci.yml passes --cov=kiro_crew --cov=sage_lib plus two bounded directories,
# and the coverage-combine job builds coverage.xml from the shard data
# files). `pytest --cov=kiro_crew` still gives a term-missing report via
# [coverage:report] below; add --cov-report for the html/xml artifacts.
# show the slowest 5 tests at the end
--durations=5
# Default to colorful output
--color=yes
# Uncomment to enforce a minimum code coverage threshold.
# --cov-fail-under 50
# `src/kiro_crew/apps/builtins` is here because five builtin apps ship their test suites
# INSIDE the package (next to the code they cover) rather than in `test/`. Without this path
# those ~3780 tests ran only when someone targeted them explicitly, so CI was green while the
# suites guarding the ops autonomy gate — the security ceiling, the off-shift refusal, the
# credential redaction floors — never executed on a pull request at all. Found in review.
#
# Scoped to the builtins dir rather than all of `src` so pytest does not walk the vendored
# llama-cpp tree or treat unrelated modules as collection roots.
testpaths = test src/kiro_crew/apps/builtins
looponfailroots = src test
# Additional coverage.py settings. The parallel flag and source values let
# pytest-cov alias the installed-package absolute paths back to the relative
# ones in your package source.
[coverage:run]
branch = true
parallel = true
# Store measured paths relative to the working directory (the repo root, where
# pytest runs) instead of absolute. The backend shards and the Coverage
# Combine job are separate runners with separate checkouts: GitHub-hosted
# runners happen to share /home/runner/work/<repo>/<repo>, but the
# CodeBuild-hosted runner (docs/ci/ci-and-reviews.md, "CodeBuild-hosted runner
# (pilot)") gives every build its own root, and absolute shard paths recorded
# under one root make `coverage xml` in the combine job abort with "No source
# for code" under another. The [coverage:paths] aliases below are relative
# patterns and cannot remap an absolute foreign root either. Relative data
# files combine anywhere the repo is checked out; coverage.xml filenames were
# already relative, so the gate's per-file baseline is unaffected.
relative_files = true
# Ephemeral pytest tmp fixtures fabricate checkout layouts at
# <tmp>/<name>/src/kiro_crew/agent.py. No real file is ever written there, but
# the phantom path lands in the coverage data and makes `coverage xml`/`coverage
# report` in the Coverage Combine job abort with "No source for code:
# .../agent.py" (the step runs under `bash -e`, so the non-zero exit fails the
# whole gate — and Coverage Gate then fails closed, blocking PR Readiness on
# every open PR). Never measure it.
#
# Anchor the pattern on pytest's tmp root, not on each fixture's directory name:
# test/test_agent_home_isolation.py already builds such a layout under two
# different names (kirocrew-wt-example/ via _make_linked_worktree, and a plain
# KiroCrew/ clone dir in test_does_not_decline_from_an_ordinary_clone), so a
# name-based glob has to be extended for every new fixture — and "*/KiroCrew/*"
# would be actively unsafe, because CI checks the repo out at
# /home/runner/work/KiroCrew/KiroCrew and that glob would omit all real source,
# turning the coverage gate green by measuring nothing. Nothing real is ever
# measured from a pytest temporary directory. The name-based entry is kept as a
# backstop for runs that override pytest's basetemp.
omit =
*/pytest-of-*/*
*/kirocrew-wt-example/*
*/.mount_*/*
# Test files whose bodies are UNREACHABLE on a GH runner, for a reason the runner cannot
# fix: each carries `skipif(not userns_available())` on the tests that need a namespace
# sandbox, and a runner denies `unshare(CLONE_NEWNS)`. A skipped test's lines are never
# executed, so measuring them charges the denominator for code the measuring host cannot
# reach -- `test_ledger_sync_git.py` measured 16% (65/405) on CI for exactly that reason.
#
# This is NOT the old "CI deselects these files" list, which covered eleven files and is
# gone: ci.yml's ordinary shards plus the hosted IPv6 lane retain the full test
# population. All eleven sandbox files report their capability skips, and the
# five without a sandbox guard are measured normally. What remains is the narrower and
# checkable rule that test/test_coverage_omit_contract.py enforces -- an omitted test file
# must carry a capability guard CI cannot satisfy, and a pattern here may never match
# product code.
#
# The proper fix is upstream of coverage: `backend-test-sandbox` clears the AppArmor
# restriction, so measuring THAT job would reach these lines. It runs `--no-cov` today.
*/ops_mission_control/tests/test_ledger_sync_git.py
*/ops_mission_control/tests/test_schedule_file.py
*/auto_improvement/tests/test_lint_findings.py
*/auto_improvement/tests/test_github_profile.py
*/auto_improvement/tests/test_profile_capture.py
*/auto_improvement/tests/test_runner.py
[coverage:paths]
source =
src/
build/lib/*/site-packages/
# Code Review Sage puts its OWN app root on sys.path (backend/routes.py and
# sage_lib/*.py do this so the app also runs standalone as
# `python3 sage_lib/learning.py`), so its 27-file suite imports the library as
# the TOP-LEVEL package `sage_lib` -- `from sage_lib import learning` -- not as
# kiro_crew.apps.builtins.code_review_sage.sage_lib.learning.
#
# CI keeps the kiro_crew and sage_lib package-name boundary, adding only the
# crew packaging and Sage tests directories for their synthetic/app-local names.
# Selecting all of src/kiro_crew also admits standalone scripts and vendored code.
# This paths entry collapses the top-level spelling ("sage_lib/learning.py") and
# the in-package spelling onto ONE canonical file during combine, avoiding
# duplicate denominator entries. Keep it for data produced by either spelling.
sagelib =
src/kiro_crew/apps/builtins/code_review_sage/sage_lib
*/code_review_sage/sage_lib
sage_lib
# Kept here rather than as an addopts --cov-report so that an explicit
# `pytest --cov=kiro_crew` still shows uncovered lines now that coverage is
# opt-in.
[coverage:report]
show_missing = true
# Also omit at report time: the Coverage Combine job reads shards produced by
# the test job, and `[coverage:run] omit` only governs collection. Without this
# a shard that already recorded the phantom fixture path would still trip
# `coverage xml`/`coverage report` with "No source for code". Keep both in sync.
omit =
*/pytest-of-*/*
*/kirocrew-wt-example/*
*/.mount_*/*
# Same capability-guarded test files as [coverage:run] omit above -- repeated here because
# Coverage Combine reads shard data and reports it in a separate process, where only
# report-time omit applies. Kept in sync by test/test_coverage_omit_contract.py.
*/ops_mission_control/tests/test_ledger_sync_git.py
*/ops_mission_control/tests/test_schedule_file.py
*/auto_improvement/tests/test_lint_findings.py
*/auto_improvement/tests/test_github_profile.py
*/auto_improvement/tests/test_profile_capture.py
*/auto_improvement/tests/test_runner.py
[coverage:html]
directory = build/coverage
[coverage:xml]
output = build/coverage/coverage.xml
[flake8]
# extend-ignore (not ignore) so pycodestyle's default-ignore list — which
# includes the black-compatible codes E226/E24/E704/W504 — stays in effect.
# Using bare `ignore =` would REPLACE those defaults and start flagging e.g.
# E226 on f-string arithmetic (`{i+1}`), which black intentionally does not space.
extend-ignore =
# Not pep8, black adds whitespace before ':'
E203,
# Not pep8, black adds line break before binary operator
W503,
# After auto-formatting, the only remaining long lines do not matter; ignore.
E501,
max_line_length = 100
# The B9 adversarial workflow corpus is hostile-script DATA loaded by
# test_workflows_malicious.py, not code: deliberate style violations and even
# a deliberately-invalid format string (F521) are the payload, not defects.
extend-exclude = test/workflows/malicious
# Vendored third-party code (llama-cpp-python) must never be linted —
# keeps diffs against upstream wheels clean for upgrades.
exclude =
src/kiro_crew/_vendor
per-file-ignores =
# _ensure_ssl_certs() must run before any library caches its SSL context
src/kiro_crew/cli.py: E402
src/kiro_crew/__main__.py: E402
src/kiro_crew/mcp_gateway/gatewayd.py: E402
# Pre-existing shapes in the crew container's own suite, which moves in with the
# image source it covers rather than being rewritten for this tree.
#
# F811: the suite shares fixtures by importing them across test modules
# (``from .test_front_proxy import backend, env``), and pyflakes reads each test's
# ``env`` PARAMETER as a redefinition of the imported name. It fires once per TEST,
# not on the import, so no noqa on the import line can reach it -- the alternative is
# six inline suppressions on six unmodified test signatures.
src/kiro_crew/apps/builtins/aws_control/crew/runtime/container_tests/test_front_transcript_fetch.py: F811
# E402: a second import block sits mid-file, after the tests for the first half,
# introducing the modules the layout tests below it need. That is the file's own
# structure, and reordering it would change a suite this move carries unchanged.
src/kiro_crew/apps/builtins/aws_control/crew/runtime/container_tests/test_supervisor_main.py: E402
# The security facade re-exports every name its submodules own, private
# helpers included, because `kiro_crew.security` is the only import path and
# callers reach those names as attributes of it. A re-export is an import
# this file deliberately does not use, which is precisely what F401 reports,
# so the check has nothing to say here: the property that matters instead is
# completeness, asserted against the frozen manifest by
# test_security_facade.py.
src/kiro_crew/security/__init__.py: F401
# The app routes facade keeps its pre-split import header: importers and patch targets
# reach those names as attributes of kiro_crew.apps.routes, while most readers moved to
# the routes_* owners. test_routes_facade.py accounts for every import it binds.
src/kiro_crew/apps/routes.py: F401
# The dashboard chat runner imports what its chat_turn owners read: compose()
# runs every owner function on the runner's globals, so an import whose only
# reader moved to an owner is read by code in another file, which F401 cannot
# see. test_chat_runner_compose_binding.py asserts every import is read.
src/kiro_crew/dashboard/chat_runner.py: F401
# The Slack gateway facade binds every global its composed gateway_runtime owners
# read: their functions run on its namespace, so an import no facade function reads
# is still a live name. test_gateway_runtime_bindings.py asserts the property F401
# stands in for here -- every import is read by a facade or owner function.
src/kiro_crew/slack/gateway.py: F401
# The native Slack handler facade is the same shape: its handler_runtime owners run on
# its namespace, so an import only an owner function reads is still a live name.
# test_handler_turn.py asserts what F401 stands for here -- every facade import is
# read by the facade or an owner, or is one of the owner names the facade exported
# at the base for other modules to read (a frozen list there).
src/kiro_crew/slack/handler.py: F401
# The config sections facade keeps every import it bound before its owners moved
# out, because callers and tests read those names as attributes of
# `kiro_crew.config.sections`; its own code reads almost none of them. The property
# F401 stands in for -- no import the facade does not mean to offer -- is the frozen
# import inventory in test_sections_facade.py.
src/kiro_crew/config/sections.py: F401
# The session-handle facade keeps every import it bound before AcpSessionHandle's
# members moved to the session_handle_* owners, because callers and tests read and
# patch those names as attributes of `kiro_crew.acp.session_handle`; its own code
# reads few of them. The property F401 stands in for -- no import the facade does
# not mean to offer -- is the frozen import inventory in
# test_session_handle_bindings.py.
src/kiro_crew/acp/session_handle.py: F401
# The runtime facade keeps every import it bound before AcpRuntime's members moved to
# the runtime_* owners, because callers and tests read and patch those names as
# attributes of `kiro_crew.acp.runtime`; its own code reads few of them. The property
# F401 stands in for -- no import the facade does not mean to offer -- is the import
# check in test_runtime_bindings.py (a BASE name, glue, owner-defined, or read).
src/kiro_crew/acp/runtime.py: F401
# The validation facade keeps the import header it had before its owners moved out
# to validation_parts/, because callers and tests read those names as attributes of
# `kiro_crew.validation`; its own code reads none of them. The property F401 stands
# in for -- no import the facade does not mean to offer -- is the frozen import
# inventory in test_validation_parts_facade.py.
src/kiro_crew/validation.py: F401
# The chat folders facade keeps the import header it had before its owners moved out
# to chat_folders_<role>.py, because callers and tests read and patch those names as
# attributes of `kiro_crew.dashboard.chat_folders`; its own code reads few of them.
# The property F401 stands in for -- no import the facade does not mean to offer -- is
# the frozen import inventory in test_chat_folders_facade.py.
src/kiro_crew/dashboard/chat_folders.py: F401
# The MCP server management facade keeps its import header beside the code it keeps
# (the mcp.json file lock and the routes that take it): importers and patch targets
# reach those names as attributes of kiro_crew.dashboard.handlers.mcp, while most
# readers live in the mcp_<role> owners. test_mcp_handler_facade.py accounts for
# every import it binds, and its planted-import self-test shows the census can fail.
src/kiro_crew/dashboard/handlers/mcp.py: F401
# The chat persistence facade binds every name its composed chat_persistence_parts
# read: their functions run on its namespace, so an import only a part reads is still
# a live name. The property F401 stands in for is the frozen import inventory in
# test_chat_persistence_parts_composition_contract.py.
src/kiro_crew/dashboard/chat_persistence.py: F401
# The CLI commands facade keeps the import header it had before its handlers moved
# out to the cli_commands_* owners, because callers and tests read and patch those
# names as attributes of `kiro_crew.cli_commands`. test_cli_commands_split_facade.py
# stands in for F401: it freezes that header and requires each local import be read.
src/kiro_crew/cli_commands.py: F401
# The cli_server and mcp_shared facades keep every import they bound before their
# owners moved out, because callers and tests read and patch those names as
# attributes of the facade, and a patch through it reaches every owner holding the
# name; their own code reads few of them. The property F401 stands in for is the
# frozen import inventory in test_cli_server_facade.py and test_mcp_shared_facade.py.
src/kiro_crew/cli_server.py: F401
src/kiro_crew/mcp_shared.py: F401
# The Slack events and interactions facades keep the import headers they had before
# their code moved to the events_* and interactions_* owners beside them, because
# callers and tests read and patch those names as attributes of the facade, and a
# patch through it reaches every owner holding the name; their own code reads only
# part of them. The property F401 stands in for is the import inventory in
# test_events_facade.py and test_interactions_facade.py.
src/kiro_crew/slack/events.py: F401
src/kiro_crew/slack/interactions.py: F401
# The core dashboard handlers facade keeps the import header it had before its owners
# moved out to core_<role>.py, because callers and tests read and patch those names as
# attributes of `kiro_crew.dashboard.handlers.core`, and a patch through it reaches every
# owner holding the name; its own routes read few of them. The property F401 stands in
# for -- no import the facade does not mean to offer -- is the import inventory in
# test_core_handlers_facade.py.
src/kiro_crew/dashboard/handlers/core.py: F401
# The cli_doctor facade keeps every import it bound before its rows moved to the
# cli_doctor_parts owners, because those owners' functions run on its globals and
# callers and tests read and patch the names as attributes of `kiro_crew.cli_doctor`;
# its own code reads few of them. The session_ledger facade keeps its import header
# for the same reason, and a patch through it reaches every owner holding the name.
# The property F401 stands in for is the frozen import inventory in
# test_cli_doctor_parts.py and test_session_ledger_facade.py.
src/kiro_crew/cli_doctor.py: F401
src/kiro_crew/session_ledger.py: F401
# The agent facade keeps every import it bound before its spec code moved to the
# agent_parts owners, and binds each name they define, because those owners' functions
# run on its globals and callers and tests read and patch the names as attributes of
# `kiro_crew.agent`; its own code reads few of them. The property F401 stands in for is
# test_agent_parts.py::test_the_facade_imports_nothing_the_family_does_not_account_for.
src/kiro_crew/agent.py: F401
# The namespace launcher program's module runs its sandbox_launcher_parts functions on
# its globals, as the child runs the program as one namespace, so an import in its kept
# head that only a part reads is still a live name; those lines are the program's
# rendered bytes and carry no noqa. The property F401 stands in for is
# test_sandbox_launcher_program_parts.py::test_every_facade_import_is_accounted_for.
src/kiro_crew/sandbox_launcher_program.py: F401
# The portability, pinned_fs and subagent_persistence facades keep every import they
# bound before their owners moved out, because callers and tests read and patch those
# names as attributes of the facade, and a patch through it reaches every owner holding
# the name; their own code reads only some of them. The property F401 stands in for is
# the frozen import inventory in test_portability_facade.py, test_pinned_fs_facade.py
# and test_subagent_persistence_facade.py.
src/kiro_crew/portability.py: F401
src/kiro_crew/pinned_fs.py: F401
src/kiro_crew/subagent_persistence.py: F401
# The Code Review Sage routes facade keeps its pre-split import header: its
# routes_parts handlers are composed onto its globals, so an import whose only reader
# moved to a part is read by code in another file, which F401 cannot see. The most
# specific row wins, so the builtin apps' E128 is repeated here.
# Its tests/test_routes_parts_composition_contract.py accounts for every import it binds.
src/kiro_crew/apps/builtins/code_review_sage/backend/routes.py: E128,F401
# Builtin app backends use compact continuation indent style
src/kiro_crew/apps/builtins/*: E128
# Uncomment to enforce a maximum cyclomatic complexity - more info https://en.wikipedia.org/wiki/Cyclomatic_complexity
# max_complexity=10