kanibako-cli 1.8.0.dev98__tar.gz → 1.8.0rc2__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.
Files changed (291) hide show
  1. {kanibako_cli-1.8.0.dev98/src/kanibako_cli.egg-info → kanibako_cli-1.8.0rc2}/PKG-INFO +1 -1
  2. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/README.md +49 -34
  3. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/pyproject.toml +5 -1
  4. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/__init__.py +1 -1
  5. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/agent_ref.py +5 -1
  6. kanibako_cli-1.8.0rc2/src/kanibako/box_lifecycle.py +232 -0
  7. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/box_supervisor.py +544 -19
  8. kanibako_cli-1.8.0rc2/src/kanibako/channels/channels.py +353 -0
  9. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/channels/helper_listener.py +17 -4
  10. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/channels/helpers.py +19 -6
  11. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/cli.py +20 -5
  12. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/commands/agent_cmd.py +137 -50
  13. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/commands/archive.py +14 -2
  14. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/commands/box/_duplicate.py +81 -43
  15. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/commands/box/_lifecycle.py +413 -93
  16. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/commands/box/_parser.py +64 -11
  17. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/commands/clean.py +24 -8
  18. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/commands/code_cmd.py +125 -19
  19. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/commands/diagnose.py +145 -4
  20. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/commands/flags.py +170 -179
  21. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/commands/helper_cmd.py +4 -2
  22. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/commands/restore.py +1 -1
  23. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/commands/setup_cmd.py +49 -9
  24. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/commands/start.py +864 -1012
  25. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/commands/stop.py +12 -3
  26. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/commands/system_cmd.py +49 -35
  27. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/commands/workset_cmd.py +195 -41
  28. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/data/core-defaults.yaml +7 -8
  29. kanibako_cli-1.8.0rc2/src/kanibako/data/global/KICKOFF.md +18 -0
  30. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/data/global/rom/COLLECTION.md +7 -10
  31. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/data/global/rom/bible/ROM_CONTENTS.md +7 -7
  32. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/data/global/rom/bible/box/directives/ROM_BOX.md +2 -1
  33. kanibako_cli-1.8.0rc2/src/kanibako/data/global/rom/bible/general/directives/ROM_GENERAL.md +112 -0
  34. kanibako_cli-1.8.0rc2/src/kanibako/data/global/rom/bible/general/scripts/hooks/clear-end.sh +12 -0
  35. kanibako_cli-1.8.0rc2/src/kanibako/data/global/rom/bible/general/scripts/hooks/clear-start.sh +12 -0
  36. kanibako_cli-1.8.0rc2/src/kanibako/data/global/rom/bible/general/scripts/hooks/compact.sh +12 -0
  37. kanibako_cli-1.8.0rc2/src/kanibako/data/global/rom/bible/general/scripts/hooks/edited.sh +7 -0
  38. kanibako_cli-1.8.0rc2/src/kanibako/data/global/rom/bible/general/scripts/hooks/end.sh +12 -0
  39. kanibako_cli-1.8.0rc2/src/kanibako/data/global/rom/bible/general/scripts/hooks/resume.sh +12 -0
  40. kanibako_cli-1.8.0rc2/src/kanibako/data/global/rom/bible/general/scripts/hooks/startup.sh +12 -0
  41. kanibako_cli-1.8.0rc2/src/kanibako/data/global/rom/bible/general/scripts/hooks/stop.sh +7 -0
  42. kanibako_cli-1.8.0rc2/src/kanibako/data/global/rom/bible/general/scripts/util/pid-add.sh +14 -0
  43. kanibako_cli-1.8.0rc2/src/kanibako/data/global/rom/bible/general/scripts/util/pid-rm.sh +17 -0
  44. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/data/global/rom/bible/workset/directives/ROM_WORKSET.md +2 -1
  45. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/data/global/template/agent_default/canon/handbook/directives/SYS_AGENT.md +3 -3
  46. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/data/global/template/box/canon/handbook/directives/SYS_BOX.md +2 -1
  47. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/data/global/template/box/home/canon/notebook/MY_CONTENTS.md +4 -6
  48. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/data/global/template/box/home/canon/notebook/directives/CONVENTIONS.md +4 -10
  49. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/data/global/template/handbook/SYS_CONTENTS.md +6 -6
  50. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/data/global/template/handbook/general/directives/SYS_GENERAL.md +10 -6
  51. kanibako_cli-1.8.0rc2/src/kanibako/data/global/template/handbook/general/directives/rules/CANON.md +60 -0
  52. kanibako_cli-1.8.0rc2/src/kanibako/data/global/template/handbook/general/directives/rules/DATAPOLICY.md +44 -0
  53. kanibako_cli-1.8.0rc2/src/kanibako/data/global/template/handbook/general/directives/rules/INTERACTION.md +32 -0
  54. kanibako_cli-1.8.0rc2/src/kanibako/data/global/template/handbook/general/procedures/USING_CHANNELS.md +28 -0
  55. kanibako_cli-1.8.0rc2/src/kanibako/data/global/template/handbook/general/scripts/behavior/check-comms.sh +74 -0
  56. kanibako_cli-1.8.0rc2/src/kanibako/data/global/template/handbook/general/scripts/hooks/clear-end.sh +8 -0
  57. kanibako_cli-1.8.0rc2/src/kanibako/data/global/template/handbook/general/scripts/hooks/clear-start.sh +8 -0
  58. kanibako_cli-1.8.0rc2/src/kanibako/data/global/template/handbook/general/scripts/hooks/compact.sh +8 -0
  59. kanibako_cli-1.8.0rc2/src/kanibako/data/global/template/handbook/general/scripts/hooks/edited.sh +7 -0
  60. kanibako_cli-1.8.0rc2/src/kanibako/data/global/template/handbook/general/scripts/hooks/end.sh +8 -0
  61. kanibako_cli-1.8.0rc2/src/kanibako/data/global/template/handbook/general/scripts/hooks/resume.sh +8 -0
  62. kanibako_cli-1.8.0rc2/src/kanibako/data/global/template/handbook/general/scripts/hooks/startup.sh +8 -0
  63. kanibako_cli-1.8.0rc2/src/kanibako/data/global/template/handbook/general/scripts/hooks/stop.sh +8 -0
  64. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/data/global/template/workset/canon/handbook/directives/SYS_WORKSET.md +7 -9
  65. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/data/keyspace-manifest.yaml +216 -528
  66. kanibako_cli-1.8.0rc2/src/kanibako/errors.py +84 -0
  67. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/kuid.py +17 -37
  68. kanibako_cli-1.8.0rc2/src/kanibako/launch/box_identity.py +231 -0
  69. kanibako_cli-1.8.0rc2/src/kanibako/launch/box_resolve.py +253 -0
  70. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/launch/creds_watcher.py +7 -1
  71. kanibako_cli-1.8.0rc2/src/kanibako/launch/journal.py +158 -0
  72. kanibako_cli-1.8.0rc2/src/kanibako/launch/shells.py +161 -0
  73. kanibako_cli-1.8.0rc2/src/kanibako/launch/templates.py +1174 -0
  74. kanibako_cli-1.8.0rc2/src/kanibako/persona_store.py +333 -0
  75. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/project/__init__.py +2 -2
  76. kanibako_cli-1.8.0rc2/src/kanibako/project/import_reconcile.py +269 -0
  77. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/project/names.py +14 -5
  78. kanibako_cli-1.8.0rc2/src/kanibako/project/registry_store.py +238 -0
  79. kanibako_cli-1.8.0rc2/src/kanibako/project/workset.py +1058 -0
  80. kanibako_cli-1.8.0rc2/src/kanibako/project/workset_registry.py +245 -0
  81. kanibako_cli-1.8.0rc2/src/kanibako/proxy/__init__.py +36 -0
  82. kanibako_cli-1.8.0rc2/src/kanibako/proxy/server.py +410 -0
  83. kanibako_cli-1.8.0rc2/src/kanibako/proxy/sse.py +178 -0
  84. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/runtime/container.py +68 -12
  85. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/scripts/helper-init.sh +6 -6
  86. kanibako_cli-1.8.0rc2/src/kanibako/scripts/import-directives.py +1094 -0
  87. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/settings/__init__.py +10 -1
  88. kanibako_cli-1.8.0rc2/src/kanibako/settings/agent_config.py +255 -0
  89. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/settings/agent_defaults.py +1 -1
  90. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/settings/agent_file.py +246 -239
  91. kanibako_cli-1.8.0rc2/src/kanibako/settings/agent_representation.py +243 -0
  92. kanibako_cli-1.8.0rc2/src/kanibako/settings/agent_select.py +188 -0
  93. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/settings/config.py +314 -90
  94. kanibako_cli-1.8.0rc2/src/kanibako/settings/config_dest.py +410 -0
  95. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/settings/config_display.py +138 -75
  96. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/settings/config_interface.py +487 -53
  97. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/settings/config_io.py +30 -77
  98. kanibako_cli-1.8.0rc2/src/kanibako/settings/config_keys.py +1902 -0
  99. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/settings/core_defaults.py +13 -4
  100. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/settings/defaults_inventory.py +100 -19
  101. kanibako_cli-1.8.0rc2/src/kanibako/settings/kb_store.py +60 -0
  102. kanibako_cli-1.8.0rc2/src/kanibako/settings/keyspace_manifest.py +52 -0
  103. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/settings/keystore.py +59 -38
  104. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/settings/paths.py +445 -128
  105. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/settings/paths_defaults.py +48 -25
  106. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/settings/settings_assemble.py +392 -54
  107. kanibako_cli-1.8.0rc2/src/kanibako/settings/settings_categories.py +811 -0
  108. kanibako_cli-1.8.0rc2/src/kanibako/settings/settings_cli_level.py +154 -0
  109. kanibako_cli-1.8.0rc2/src/kanibako/settings/settings_configset.py +138 -0
  110. kanibako_cli-1.8.0rc2/src/kanibako/settings/settings_expand.py +538 -0
  111. kanibako_cli-1.8.0rc2/src/kanibako/settings/settings_keyspace.py +1800 -0
  112. kanibako_cli-1.8.0rc2/src/kanibako/settings/settings_keyspace_probe.py +363 -0
  113. kanibako_cli-1.8.0rc2/src/kanibako/settings/settings_launch.py +2271 -0
  114. kanibako_cli-1.8.0rc2/src/kanibako/settings/settings_merge.py +169 -0
  115. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/settings/settings_prefs.py +232 -229
  116. kanibako_cli-1.8.0rc2/src/kanibako/settings/settings_resolve.py +433 -0
  117. kanibako_cli-1.8.0rc2/src/kanibako/settings/settings_views.py +543 -0
  118. kanibako_cli-1.8.0rc2/src/kanibako/settings/store_collapse.py +975 -0
  119. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/settings/store_shape.py +14 -13
  120. kanibako_cli-1.8.0rc2/src/kanibako/settings/workset_dirkeys.py +143 -0
  121. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/targets/__init__.py +26 -8
  122. kanibako_cli-1.8.0rc2/src/kanibako/targets/assembly.py +433 -0
  123. kanibako_cli-1.8.0rc2/src/kanibako/targets/base.py +618 -0
  124. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/vscode/vscode_config.py +24 -11
  125. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/vscode/vscode_remote.py +8 -2
  126. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2/src/kanibako_cli.egg-info}/PKG-INFO +1 -1
  127. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako_cli.egg-info/SOURCES.txt +29 -5
  128. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_box_supervisor.py +949 -0
  129. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_canon_delivery.py +2 -2
  130. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_canon_lifecycle_deletion.py +1 -1
  131. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_categories_live.py +740 -23
  132. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_category_collisions.py +22 -9
  133. kanibako_cli-1.8.0rc2/tests/test_claude_seed_hooks.py +301 -0
  134. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_cli.py +39 -11
  135. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_cli_exitcodes.py +9 -4
  136. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_create_recovery.py +2 -2
  137. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_delivery_manifest.py +6 -7
  138. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_env_cmd.py +11 -11
  139. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_flawed_oracle.py +51 -17
  140. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_fork.py +90 -3
  141. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_helper_cmd.py +17 -2
  142. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_import.py +210 -42
  143. kanibako_cli-1.8.0rc2/tests/test_import_directives.py +1484 -0
  144. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_import_recovery.py +17 -14
  145. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_init_cmd.py +18 -10
  146. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_install_integration.py +10 -7
  147. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_instructions_bind.py +80 -32
  148. kanibako_cli-1.8.0rc2/tests/test_keyspec_extract.py +174 -0
  149. kanibako_cli-1.8.0rc2/tests/test_keystore_census.py +402 -0
  150. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_lifecycle_integration.py +4 -15
  151. kanibako_cli-1.8.0rc2/tests/test_meta_pin.py +135 -0
  152. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_persona_config_set.py +30 -16
  153. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_persona_store.py +1 -1
  154. kanibako_cli-1.8.0rc2/tests/test_plugin_import_compat.py +367 -0
  155. kanibako_cli-1.8.0rc2/tests/test_plugin_store_isolation.py +254 -0
  156. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_resource_scoping.py +17 -9
  157. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_safety_invariants.py +3 -3
  158. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_seed_hostdest.py +26 -6
  159. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_setup_cmd.py +30 -18
  160. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_status.py +2 -2
  161. kanibako_cli-1.8.0.dev98/src/kanibako/agent_config.py +0 -86
  162. kanibako_cli-1.8.0.dev98/src/kanibako/agent_defaults.py +0 -56
  163. kanibako_cli-1.8.0.dev98/src/kanibako/box_lifecycle.py +0 -285
  164. kanibako_cli-1.8.0.dev98/src/kanibako/channels/channels.py +0 -264
  165. kanibako_cli-1.8.0.dev98/src/kanibako/data/global/KICKOFF.md +0 -2
  166. kanibako_cli-1.8.0.dev98/src/kanibako/data/global/rom/bible/general/directives/ROM_GENERAL.md +0 -95
  167. kanibako_cli-1.8.0.dev98/src/kanibako/data/global/template/handbook/general/directives/rules/CANON.md +0 -91
  168. kanibako_cli-1.8.0.dev98/src/kanibako/data/global/template/handbook/general/directives/rules/DATAPOLICY.md +0 -51
  169. kanibako_cli-1.8.0.dev98/src/kanibako/data/global/template/handbook/general/directives/rules/INTERACTION.md +0 -59
  170. kanibako_cli-1.8.0.dev98/src/kanibako/errors.py +0 -118
  171. kanibako_cli-1.8.0.dev98/src/kanibako/launch/box_identity.py +0 -302
  172. kanibako_cli-1.8.0.dev98/src/kanibako/launch/box_resolve.py +0 -328
  173. kanibako_cli-1.8.0.dev98/src/kanibako/launch/journal.py +0 -201
  174. kanibako_cli-1.8.0.dev98/src/kanibako/launch/shells.py +0 -196
  175. kanibako_cli-1.8.0.dev98/src/kanibako/launch/templates.py +0 -1252
  176. kanibako_cli-1.8.0.dev98/src/kanibako/persona_store.py +0 -411
  177. kanibako_cli-1.8.0.dev98/src/kanibako/project/import_reconcile.py +0 -300
  178. kanibako_cli-1.8.0.dev98/src/kanibako/project/registry_store.py +0 -355
  179. kanibako_cli-1.8.0.dev98/src/kanibako/project/workset.py +0 -1017
  180. kanibako_cli-1.8.0.dev98/src/kanibako/project/workset_registry.py +0 -196
  181. kanibako_cli-1.8.0.dev98/src/kanibako/scripts/import-directives.py +0 -384
  182. kanibako_cli-1.8.0.dev98/src/kanibako/settings/agent_config.py +0 -235
  183. kanibako_cli-1.8.0.dev98/src/kanibako/settings/agent_representation.py +0 -342
  184. kanibako_cli-1.8.0.dev98/src/kanibako/settings/agent_select.py +0 -281
  185. kanibako_cli-1.8.0.dev98/src/kanibako/settings/config_dest.py +0 -547
  186. kanibako_cli-1.8.0.dev98/src/kanibako/settings/config_keys.py +0 -1053
  187. kanibako_cli-1.8.0.dev98/src/kanibako/settings/kb_store.py +0 -74
  188. kanibako_cli-1.8.0.dev98/src/kanibako/settings/keyspace_manifest.py +0 -63
  189. kanibako_cli-1.8.0.dev98/src/kanibako/settings/settings_categories.py +0 -1179
  190. kanibako_cli-1.8.0.dev98/src/kanibako/settings/settings_cli_level.py +0 -274
  191. kanibako_cli-1.8.0.dev98/src/kanibako/settings/settings_configset.py +0 -281
  192. kanibako_cli-1.8.0.dev98/src/kanibako/settings/settings_expand.py +0 -667
  193. kanibako_cli-1.8.0.dev98/src/kanibako/settings/settings_keyspace.py +0 -817
  194. kanibako_cli-1.8.0.dev98/src/kanibako/settings/settings_launch.py +0 -2712
  195. kanibako_cli-1.8.0.dev98/src/kanibako/settings/settings_merge.py +0 -275
  196. kanibako_cli-1.8.0.dev98/src/kanibako/settings/settings_resolve.py +0 -687
  197. kanibako_cli-1.8.0.dev98/src/kanibako/settings/settings_views.py +0 -674
  198. kanibako_cli-1.8.0.dev98/src/kanibako/settings/store_collapse.py +0 -444
  199. kanibako_cli-1.8.0.dev98/src/kanibako/settings_resolve.py +0 -109
  200. kanibako_cli-1.8.0.dev98/src/kanibako/targets/assembly.py +0 -545
  201. kanibako_cli-1.8.0.dev98/src/kanibako/targets/base.py +0 -1102
  202. kanibako_cli-1.8.0.dev98/src/kanibako/vscode_config.py +0 -140
  203. kanibako_cli-1.8.0.dev98/tests/test_credentials.py +0 -337
  204. kanibako_cli-1.8.0.dev98/tests/test_import_directives.py +0 -361
  205. kanibako_cli-1.8.0.dev98/tests/test_meta_pin.py +0 -83
  206. kanibako_cli-1.8.0.dev98/tests/test_plugin_import_compat.py +0 -314
  207. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/LICENSE.md +0 -0
  208. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/setup.cfg +0 -0
  209. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/__main__.py +0 -0
  210. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/_atomic.py +0 -0
  211. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/auth_browser.py +0 -0
  212. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/auth_parser.py +0 -0
  213. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/browser_sidecar.py +0 -0
  214. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/browser_state.py +0 -0
  215. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/bun_sea.py +0 -0
  216. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/channels/__init__.py +0 -0
  217. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/channels/helper_client.py +0 -0
  218. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/commands/__init__.py +0 -0
  219. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/commands/baseline_cmd.py +0 -0
  220. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/commands/box/__init__.py +0 -0
  221. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/commands/fork_cmd.py +0 -0
  222. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/commands/image.py +0 -0
  223. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/commands/install.py +0 -0
  224. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/commands/upgrade.py +0 -0
  225. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/commands/vault_cmd.py +0 -0
  226. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/containers/Containerfile.template-android +0 -0
  227. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/containers/Containerfile.template-dotnet +0 -0
  228. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/containers/Containerfile.template-js +0 -0
  229. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/containers/Containerfile.template-jvm +0 -0
  230. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/containers/Containerfile.template-systems +0 -0
  231. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/containers/__init__.py +0 -0
  232. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/containers/tmux.conf +0 -0
  233. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/data/__init__.py +0 -0
  234. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/data/global/template/box/home/canon/workbook/devnotes.md +0 -0
  235. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/data/global/template/box/home/canon/workbook/tasks.md +0 -0
  236. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/data/image-baseline.yaml +0 -0
  237. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/git.py +0 -0
  238. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/install_method.py +0 -0
  239. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/launch/__init__.py +0 -0
  240. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/launch/hygiene.py +0 -0
  241. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/log.py +0 -0
  242. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/plugins/__init__.py +0 -0
  243. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/py.typed +0 -0
  244. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/runtime/__init__.py +0 -0
  245. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/runtime/baseline.py +0 -0
  246. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/runtime/containerfiles.py +0 -0
  247. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/runtime/freshness.py +0 -0
  248. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/runtime/image_sharing.py +0 -0
  249. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/runtime/registry.py +0 -0
  250. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/runtime/rig_bundle.py +0 -0
  251. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/runtime/rig_meta.py +0 -0
  252. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/runtime/rig_registry.py +0 -0
  253. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/runtime/rig_resolve.py +0 -0
  254. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/runtime/rig_source.py +0 -0
  255. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/runtime/templates_image.py +0 -0
  256. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/scripts/__init__.py +0 -0
  257. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/scripts/kanibako-entry +0 -0
  258. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/scripts/kanibako-secrets.sh +0 -0
  259. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/settings/keystore_strings.py +0 -0
  260. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/snapshots.py +0 -0
  261. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/targets/credsync.py +0 -0
  262. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/targets/no_agent.py +0 -0
  263. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/tweakcc.py +0 -0
  264. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/tweakcc_cache.py +0 -0
  265. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/utils.py +0 -0
  266. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako/vscode/__init__.py +0 -0
  267. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako_cli.egg-info/dependency_links.txt +0 -0
  268. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako_cli.egg-info/entry_points.txt +0 -0
  269. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako_cli.egg-info/requires.txt +0 -0
  270. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/src/kanibako_cli.egg-info/top_level.txt +0 -0
  271. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_agent_ref.py +0 -0
  272. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_agent_resolution.py +0 -0
  273. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_archive_restore_integration.py +0 -0
  274. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_atomic.py +0 -0
  275. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_auth_browser.py +0 -0
  276. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_auth_parser.py +0 -0
  277. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_box_lifecycle.py +0 -0
  278. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_browser_sidecar.py +0 -0
  279. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_browser_state.py +0 -0
  280. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_bun_sea.py +0 -0
  281. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_comms.py +0 -0
  282. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_error_messages.py +0 -0
  283. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_explicit_create.py +0 -0
  284. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_git.py +0 -0
  285. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_kuid.py +0 -0
  286. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_log.py +0 -0
  287. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_protected_tree_cleanup.py +0 -0
  288. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_snapshots.py +0 -0
  289. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_start_integration.py +0 -0
  290. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_tweakcc.py +0 -0
  291. {kanibako_cli-1.8.0.dev98 → kanibako_cli-1.8.0rc2}/tests/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kanibako-cli
3
- Version: 1.8.0.dev98
3
+ Version: 1.8.0rc2
4
4
  Summary: Run AI coding agents in rootless containers with per-project isolation
5
5
  Requires-Python: >=3.11
6
6
  License-File: LICENSE.md
@@ -225,7 +225,7 @@ shortcuts for common operations:
225
225
 
226
226
  | Subcommand | Description |
227
227
  |------------|-------------|
228
- | `workset create [path]` | Create working set (`--name`, `--standalone`, `--image`, `--no-vault`, `--distinct-auth`) |
228
+ | `workset create [path]` | Create working set (`--name`, `--image`, `--no-vault`, `--distinct-auth`) |
229
229
  | `workset list` / `workset ls` | List working sets (`-q`) |
230
230
  | `workset info` / `workset inspect` | Working set details |
231
231
  | `workset rm` / `workset delete` | Remove working set (`--purge`, `--force`) |
@@ -505,8 +505,8 @@ and cannot be used as a named-workset name.
505
505
 
506
506
  ```
507
507
  $XDG_DATA_HOME/kanibako/primary_workset/
508
- ├── settings.yaml
509
- ├── boxes/{name}/{home/ → ~/ , settings.yaml}
508
+ ├── workset.yaml
509
+ ├── boxes/{name}/{home/ → ~/ , box.yaml}
510
510
  ├── vault/{ro,rw}/{name}/ → ~/vault/{ro,rw}
511
511
  └── logs/{name}.jsonl
512
512
  # the box WORKSPACE stays external: your real project dir → ~/workspace
@@ -515,7 +515,7 @@ $XDG_DATA_HOME/kanibako/primary_workset/
515
515
  ### Named workset
516
516
 
517
517
  A workset is a *named* project group rooted at a directory you pick. It groups
518
- related projects under one human-readable root, with a single `<root>/settings.yaml`
518
+ related projects under one human-readable root, with a single `<root>/workset.yaml`
519
519
  (identity + member list + a group-level settings/auth tier that member boxes
520
520
  inherit; see [Configuration](#configuration)). A workset name is a shared
521
521
  address and must be unique -- a collision at create/import time is refused.
@@ -529,8 +529,8 @@ kanibako
529
529
 
530
530
  ```
531
531
  {workset}/
532
- ├── settings.yaml
533
- ├── boxes/{name}/{home/ → ~/ , settings.yaml}
532
+ ├── workset.yaml
533
+ ├── boxes/{name}/{home/ → ~/ , box.yaml}
534
534
  ├── workspaces/{name}/ → ~/workspace
535
535
  ├── vault/{ro,rw}/{name}/ → ~/vault/{ro,rw}
536
536
  └── logs/{name}.jsonl
@@ -559,9 +559,9 @@ kanibako box register ~/myproj # or opt in afterwards
559
559
 
560
560
  ```
561
561
  {project}/ ← project root
562
- ├── settings.yaml ← box metadata (at the root)
562
+ ├── workset.yaml ← workset tier (degenerate workset at the root)
563
563
  ├── workspace/ → ~/workspace (a subdir, not the root)
564
- ├── box_data/{home/ → ~/ , {name}.jsonl}
564
+ ├── box_data/{home/ → ~/ , box.yaml, {name}.jsonl}
565
565
  └── vault/{ro,rw}/ → ~/vault/{ro,rw}
566
566
  ```
567
567
 
@@ -744,31 +744,33 @@ support `shell.d/` on the next launch.
744
744
  ## Agent Configuration
745
745
 
746
746
  Each agent gets a YAML configuration file inside its per-agent store directory
747
- at `$XDG_DATA_HOME/kanibako/agents/{agent}/settings.yaml`. The file is
747
+ at `$XDG_DATA_HOME/kanibako/agents/{agent}/agent.yaml`. The file is
748
748
  generated automatically on first use (via the target plugin's
749
749
  `generate_agent_config()` method) and can be edited afterwards.
750
750
 
751
751
  ```yaml
752
- agent:
752
+ self:
753
753
  name: "Claude Code"
754
- run_args: [] # extra CLI args prepended on every launch
754
+ run_args: ["--verbose"] # extra CLI args prepended on every launch (omit if none)
755
755
  model: "opus" # agent-specific state knobs (e.g. --model for Claude)
756
756
  access: "permissive"
757
- env:
758
- # KEY: "value" # raw env vars injected into the box
759
- tweakcc:
760
- # enabled: false # enable tweakcc binary patching
761
- # config: "~/.tweakcc/config.json" # external tweakcc config file
757
+ env:
758
+ # KEY: "value" # raw env vars injected into the box
759
+ transform_settings:
760
+ # enabled: false # enable tweakcc binary patching
761
+ # config: "~/.tweakcc/config.json" # external tweakcc config file
762
762
  ```
763
763
 
764
764
  **Sections:**
765
- - `agent:` -- identity and defaults (`name`, `run_args`) plus runtime state
766
- knobs translated by the target plugin into CLI args and env vars (e.g. Claude
767
- maps `model` -> `--model`). Effective state resolves across the settings
768
- cascade `system < agent.<agent> < workset < box` with the target's declared
769
- defaults as the floor.
770
- - `env:` -- environment variables injected into the box
771
- - `tweakcc:` -- optional tweakcc integration for binary patching
765
+ - `self:` -- the file's root table, which stands for the agent whose file it is
766
+ (`agent.<agent>`); it is a spelling of this file only and has no CLI form. It
767
+ holds identity and defaults (`name`, `run_args`) plus runtime state knobs
768
+ translated by the target plugin into CLI args and env vars (e.g. Claude maps
769
+ `model` -> `--model`). Effective state resolves across the settings cascade
770
+ `system < agent.<agent> < workset < box` with the target's declared defaults
771
+ as the floor.
772
+ - `self.env:` -- environment variables injected into the box
773
+ - `self.transform_settings:` -- optional tweakcc integration for binary patching
772
774
  (see [docs/tweakcc.md](docs/tweakcc.md))
773
775
 
774
776
  Per-agent common dirs/caches are declared by the plugin (`agent.<agent>.common` /
@@ -911,12 +913,18 @@ Later sources override earlier ones when two plugins register the same name.
911
913
  |------|----------|----------|
912
914
  | 1. Entry points | `kanibako.agents` entry point group + `kanibako.plugins.*` namespace scan | Pip-installed packages and bind-mounted plugins in nested containers |
913
915
  | 2. User directory | `~/.local/share/kanibako/plugins/*.py` | Personal plugins shared across all projects |
914
- | 3. Project directory | `{project}/.kanibako/plugins/*.py` | Project-specific plugins |
916
+ | 3. Project directory | `{project}/box_data/plugins/*.py` | Project-specific plugins |
915
917
 
916
918
  Drop a `.py` file containing a `Target` subclass into the user or project
917
919
  plugins directory and Kanibako picks it up automatically -- no packaging or
918
920
  `pip install` needed. Files starting with `_` are skipped.
919
921
 
922
+ **A plugin that fails to load is skipped, not fatal.** If a plugin raises while
923
+ being imported -- most often because it was built against a different
924
+ `kanibako-cli` -- Kanibako names it on standard error, says the rest still works,
925
+ and carries on without it. Only that agent becomes unavailable; every other
926
+ agent, and `kanibako setup`, are unaffected.
927
+
920
928
  **Security note:** file-drop plugins run with the same permissions as
921
929
  Kanibako itself. Only place files you trust in plugin directories.
922
930
 
@@ -928,10 +936,11 @@ guide.
928
936
  pip install kanibako-target-myagent
929
937
 
930
938
  # Use a specific target
931
- kanibako box set box.agent=myagent
939
+ kanibako box set pref.system.agent=myagent
932
940
  kanibako start
933
941
 
934
- # (`crab_name` is gone -- select the agent via box.agent)
942
+ # (`crab_name` and `box.agent_name` are gone -- select the agent via
943
+ # pref.system.agent, which is the spelling kanibako's own messages print)
935
944
  ```
936
945
 
937
946
  ## Configuration
@@ -940,15 +949,17 @@ Kanibako splits **config** (layout -- *where things live*, the `system.*`
940
949
  namespace) from **settings** (behavior -- `agent.*` / `box.*` / `workset.*` plus
941
950
  the category keys). They live in separate file sets.
942
951
 
943
- **Settings** follow a 6-tier cascade (box wins among the normal tiers;
944
- `*_required` is an absolute admin cap above box), below CLI flags:
952
+ **Settings** follow a 5-tier cascade (box wins), below CLI flags:
945
953
 
946
954
  ```
947
- CLI flag > settings_required > box > workset > agent.<agent> > system > settings_base
955
+ CLI flag > box > workset > agent.<agent> > system > settings_base
948
956
  ```
949
957
 
958
+ Within the agent tier, `agent.default` supplies the all-agents fallback for any key
959
+ the active agent's own layer does not set.
960
+
950
961
  **Config** (`system.*`) is read from the config file set
951
- (`config_base < ~/.config/kanibako.yaml < config_required`). Config keys are
962
+ (`config_base < ~/.config/kanibako.yaml`). Config keys are
952
963
  **file-only** -- the CLI reads and shows them but refuses to set them (edit the
953
964
  file directly); `setup` and programmatic writers still write them.
954
965
 
@@ -987,9 +998,13 @@ All kanibako config/settings files are YAML.
987
998
 
988
999
  - **Config (global)**: `$XDG_CONFIG_HOME/kanibako.yaml` (`system.*` layout only)
989
1000
  - **System settings**: `$XDG_DATA_HOME/kanibako/global/settings.yaml`
990
- - **Workset settings**: `<workset_root>/settings.yaml`
991
- - **Per-agent settings**: `$XDG_DATA_HOME/kanibako/agents/{agent}/settings.yaml`
992
- - **Per-box settings**: `boxes/{name}/settings.yaml` (standalone: `<root>/settings.yaml`)
1001
+ - **Workset settings**: `<workset_root>/workset.yaml` (optional -- a workset root has
1002
+ one only once you set something there)
1003
+ - **Workset membership**: `<workset_root>/registry.yaml` (its boxes, as flat `name: path`
1004
+ rows -- and nothing else; a workset is NAMED by the global registry's `worksets:` section,
1005
+ never by a file under its own root)
1006
+ - **Per-agent settings**: `$XDG_DATA_HOME/kanibako/agents/{agent}/agent.yaml`
1007
+ - **Per-box settings**: `boxes/{name}/box.yaml` (standalone: `<root>/box_data/box.yaml`)
993
1008
  - **Template root**: `$XDG_DATA_HOME/kanibako/global/template/` (the `box`,
994
1009
  `workset` and `agent` moulds new stores are stamped from)
995
1010
  - **System handbook**: `$XDG_DATA_HOME/kanibako/global/canon/handbook/` -- your
@@ -1104,7 +1119,7 @@ A broadcast channel (`all/`) is available to all helpers.
1104
1119
  workspace/ # helper's working directory
1105
1120
  vault/ro/ # read-only vault share
1106
1121
  vault/rw/ # read-write vault share
1107
- playbook/scripts/ # helper-init.sh (entrypoint wrapper)
1122
+ scripts/ # helper-init.sh (entrypoint wrapper)
1108
1123
  peers/ # symlinks to peer channels
1109
1124
  all -> ../all/ # broadcast channel
1110
1125
  spawn.yaml # RO spawn budget
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "kanibako-cli"
7
- version = "1.8.0.dev98"
7
+ version = "1.8.0rc2"
8
8
  description = "Run AI coding agents in rootless containers with per-project isolation"
9
9
  requires-python = ">=3.11"
10
10
  dependencies = ["argcomplete>=3.0", "PyYAML>=6.0", "packaging>=20.0"]
@@ -102,5 +102,9 @@ markers = [
102
102
  # OF ``unshare_chown``/``unshare_chmod`` themselves: patching the subject with
103
103
  # the stub turns real assertions into false reds.
104
104
  "no_unshare_sim: never apply the protected-canon unshare simulation",
105
+ # The KeyStore census (tests/_keystore_census.py) fails a run on an undeclared
106
+ # key. A test that EXERCISES a refusal has to write one; it names the exact
107
+ # paths here, and a named path that is never written fails the run in its turn.
108
+ "writes_undeclared: this test writes the named UNDECLARED key paths on purpose",
105
109
  ]
106
110
  addopts = "-m 'not integration and not e2e'"
@@ -1,6 +1,6 @@
1
1
  """kanibako: Run AI coding agents in rootless containers with per-project isolation."""
2
2
 
3
- __version__ = "1.8.0.dev98"
3
+ __version__ = "1.8.0rc2"
4
4
 
5
5
  # Two-tier setup/config compatibility constants for the 5-band setup-completion
6
6
  # gate (design: ``plans/2026-06-23-setup-version-tiers-NEXT.md``). Both are
@@ -10,7 +10,11 @@ from __future__ import annotations
10
10
  import re
11
11
  from kanibako.errors import ConfigError
12
12
 
13
- # Persona/harness separators: one for typing [+], another internally to avoid collisions [℘]
13
+ # Persona/harness separators. ``+`` is the spelling wherever a human looks, the on-disk store
14
+ # dirname included (:func:`kanibako.settings.agent_config.store_dirname`). ``℘`` exists for ONE
15
+ # reason: a key path is split on ``.`` into ``SEGMENT_CHAR_CLASS`` segments (below), which admit
16
+ # no ``+`` — so ``agent.nav+claude.model`` would match only ``agent.nav`` and silently resolve a
17
+ # different key. A node wears ``℘`` INSIDE a key and nowhere else.
14
18
  SEPARATORS = (PLUS_SEP := "+", CANONICAL_SEP := "℘")
15
19
 
16
20
  # "Safe" characters in agent names
@@ -0,0 +1,232 @@
1
+ """Box CLIENT-ATTACHMENT detection — the shared PID-1 lifecycle primitive.
2
+
3
+ ⚑ Half of the PID-1 pair with :mod:`kanibako.box_supervisor`: PINNED FLAT,
4
+ STDLIB-ONLY, invoked in-box by a dotted literal. Do not package or move it, and
5
+ do not add a non-stdlib import.
6
+
7
+ ⚑ Every probe here is TOLERANT — an absent tmux, empty/garbled output or a
8
+ malformed ``/proc`` entry resolves to a safe falsy / ``None``, never an
9
+ exception. This module runs as PID-1; a raise takes the box down.
10
+
11
+ Reasoning, the increment map and the design refs: ``llm-docs/kanibako/box_lifecycle.py.md``.
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ import subprocess
17
+ from collections.abc import Callable, Iterable
18
+ from dataclasses import dataclass
19
+ from enum import Enum
20
+ from glob import glob
21
+ from pathlib import Path
22
+
23
+ # ---------------------------------------------------------------------------
24
+ # VS Code remote-server directory markers (canonical — shared with code_cmd).
25
+ # ---------------------------------------------------------------------------
26
+
27
+ # ⚑ ILLUSTRATIVE — the known channels, for readers. NOT the matching rule:
28
+ # :func:`is_vscode_server_path_part` is authoritative and deliberately broader,
29
+ # so editing this tuple does NOT change matching.
30
+ VSCODE_SERVER_DIR_MARKERS: tuple[str, ...] = (
31
+ ".vscode-server",
32
+ ".vscode-server-insiders",
33
+ ".vscode-server-oss",
34
+ ".cursor-server",
35
+ )
36
+
37
+
38
+ def is_vscode_server_path_part(part: str) -> bool:
39
+ """True when a single path SEGMENT names a VS Code remote-server dir.
40
+
41
+ Takes ONE path component (e.g. from :attr:`pathlib.Path.parts`), so a
42
+ caller tests each segment of a resolved/cmdline path independently.
43
+ """
44
+ return part.startswith(".vscode-server") or part == ".cursor-server"
45
+
46
+
47
+ # ---------------------------------------------------------------------------
48
+ # Pure surface detectors.
49
+ # ---------------------------------------------------------------------------
50
+
51
+ def vscode_server_present(proc_cmdlines: Iterable[str]) -> bool:
52
+ """True iff any process command line indicates a running in-box VS Code server.
53
+
54
+ PURE, over ALREADY-collected cmdlines: a cmdline counts when any
55
+ ``/``-delimited SEGMENT of it names a remote-server dir — so
56
+ ``/home/agent/.vscode-server/bin/<hash>/node`` matches while
57
+ ``/usr/bin/node`` does not. An empty iterable → ``False``.
58
+ """
59
+ for cmdline in proc_cmdlines:
60
+ if any(is_vscode_server_path_part(part) for part in cmdline.split("/")):
61
+ return True
62
+ return False
63
+
64
+
65
+ def tmux_terminal_attached(list_clients_output: str) -> bool:
66
+ """True iff ``tmux list-clients`` output shows ≥1 attached terminal client.
67
+
68
+ PURE: tmux prints one LINE per attached client and nothing otherwise.
69
+ ⚑ The CALLER must normalise any tmux error to ``""`` to keep this a pure
70
+ string test — :func:`_tmux_clients_output` is what does that.
71
+ """
72
+ return bool(list_clients_output.strip())
73
+
74
+
75
+ # ---------------------------------------------------------------------------
76
+ # Attach-state model + transition classifier.
77
+ # ---------------------------------------------------------------------------
78
+
79
+ @dataclass(frozen=True)
80
+ class AttachState:
81
+ """Immutable snapshot of which client surfaces are attached to the box.
82
+
83
+ Two surfaces today, kept as named bools so a new one is a single added
84
+ field. Frozen so a prev/cur pair is safe to hold across a watcher tick.
85
+ """
86
+
87
+ vscode_server: bool = False
88
+ tmux_terminal: bool = False
89
+
90
+ @property
91
+ def any_attached(self) -> bool:
92
+ """True when ANY client surface is currently attached."""
93
+ return self.vscode_server or self.tmux_terminal
94
+
95
+ @property
96
+ def _surfaces(self) -> tuple[bool, ...]:
97
+ """The per-surface flags, positionally stable across states.
98
+
99
+ A new surface added to this tuple needs no classifier change.
100
+ """
101
+ return (self.vscode_server, self.tmux_terminal)
102
+
103
+
104
+ class LifecycleEvent(Enum):
105
+ """The transition a watcher tick produces (consumed by E2 self-heal / D)."""
106
+
107
+ ATTACH = "attach"
108
+ DETACH = "detach"
109
+ NONE = "none"
110
+
111
+
112
+ def classify_transition(prev: AttachState, cur: AttachState) -> LifecycleEvent:
113
+ """Classify the attach-state transition ``prev`` → ``cur`` (PURE).
114
+
115
+ * DETACH — ANY surface present in ``prev`` is gone in ``cur``, even when a
116
+ DIFFERENT surface appeared in the same tick.
117
+ * ATTACH — no surface was lost AND at least one new surface appeared.
118
+ * NONE — no surface changed (includes the idempotent same-state tick).
119
+
120
+ ⚑ That DETACH bias is deliberate and safety-critical: MISSING a detach
121
+ drops a just-refreshed token, while an EXTRA detach costs only a redundant,
122
+ idempotent writeback. Do not "fix" the mixed tick — see the llm-doc.
123
+ """
124
+ lost = any(p and not c for p, c in zip(prev._surfaces, cur._surfaces))
125
+ if lost:
126
+ return LifecycleEvent.DETACH
127
+ gained = any(c and not p for p, c in zip(prev._surfaces, cur._surfaces))
128
+ if gained:
129
+ return LifecycleEvent.ATTACH
130
+ return LifecycleEvent.NONE
131
+
132
+
133
+ # ---------------------------------------------------------------------------
134
+ # Thin INJECTABLE system-probe layer (the ONLY side-effecting code).
135
+ # ---------------------------------------------------------------------------
136
+
137
+ # The subprocess-runner signature the probes call; tests inject a fake.
138
+ _Runner = Callable[..., "subprocess.CompletedProcess[str]"]
139
+
140
+
141
+ def _collect_proc_cmdlines() -> list[str]:
142
+ """Collect running-process command lines from ``/proc/*/cmdline``.
143
+
144
+ The impure companion to :func:`vscode_server_present`. Tolerant: a
145
+ vanished PID, a permission error or a kernel thread's empty cmdline is
146
+ SKIPPED, never raised.
147
+ """
148
+ cmdlines: list[str] = []
149
+ for entry in glob("/proc/[0-9]*/cmdline"):
150
+ try:
151
+ raw = Path(entry).read_bytes()
152
+ except OSError:
153
+ # PID vanished between glob and read, or unreadable — skip it.
154
+ continue
155
+ # cmdline is NUL-delimited argv (trailing NUL); decode leniently.
156
+ text = raw.replace(b"\x00", b" ").decode("utf-8", "replace").strip()
157
+ if text:
158
+ cmdlines.append(text)
159
+ return cmdlines
160
+
161
+
162
+ def _tmux_clients_output(session: str, run: _Runner) -> str:
163
+ """Return ``tmux list-clients -t <session>`` stdout, or ``""`` on any failure.
164
+
165
+ Normalises EVERY not-attached / no-tmux condition to the empty string
166
+ :func:`tmux_terminal_attached` reads as "no terminal".
167
+ ⚑ ``-F ""`` is NOT used: the default one-line-per-client output IS the
168
+ presence signal being tested.
169
+ """
170
+ try:
171
+ proc = run(
172
+ ["tmux", "list-clients", "-t", session],
173
+ capture_output=True,
174
+ text=True,
175
+ check=False,
176
+ )
177
+ except (FileNotFoundError, OSError):
178
+ return ""
179
+ if proc.returncode != 0:
180
+ return ""
181
+ return proc.stdout or ""
182
+
183
+
184
+ def snapshot_attach_state(
185
+ session: str,
186
+ *,
187
+ run: _Runner = subprocess.run,
188
+ proc_cmdlines: Iterable[str] | None = None,
189
+ ) -> AttachState:
190
+ """Probe the CURRENT client-attachment state of the box (the impure snapshot).
191
+
192
+ Composes the two pure detectors over freshly probed system state; an
193
+ explicit *proc_cmdlines* skips the ``/proc`` read entirely. ⚑ All probing
194
+ in this module is confined here and to the two ``_*`` helpers. Never
195
+ raises.
196
+ """
197
+ cmdlines = (
198
+ _collect_proc_cmdlines() if proc_cmdlines is None else list(proc_cmdlines)
199
+ )
200
+ return AttachState(
201
+ vscode_server=vscode_server_present(cmdlines),
202
+ tmux_terminal=tmux_terminal_attached(_tmux_clients_output(session, run)),
203
+ )
204
+
205
+
206
+ def canonical_tmux_session_pid(
207
+ session: str,
208
+ *,
209
+ run: _Runner = subprocess.run,
210
+ ) -> int | None:
211
+ """Best-effort PID of the tmux server hosting *session* (the "live marker").
212
+
213
+ ⚑ ``#{pid}`` is the tmux SERVER pid, not a pane or client pid. ``None``
214
+ when the session is absent, tmux is missing, or the output is unparseable.
215
+ E2 uses this to identify the canonical always-on instance.
216
+ """
217
+ try:
218
+ proc = run(
219
+ ["tmux", "display-message", "-p", "-t", session, "#{pid}"],
220
+ capture_output=True,
221
+ text=True,
222
+ check=False,
223
+ )
224
+ except (FileNotFoundError, OSError):
225
+ return None
226
+ if proc.returncode != 0:
227
+ return None
228
+ text = (proc.stdout or "").strip()
229
+ try:
230
+ return int(text)
231
+ except ValueError:
232
+ return None