blq-cli 0.11.2__tar.gz → 1.0.0__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 (194) hide show
  1. {blq_cli-0.11.2 → blq_cli-1.0.0}/.gitignore +2 -1
  2. {blq_cli-0.11.2 → blq_cli-1.0.0}/CLAUDE.md +9 -9
  3. {blq_cli-0.11.2 → blq_cli-1.0.0}/PKG-INFO +1 -1
  4. blq_cli-1.0.0/docs/api-reference.md +601 -0
  5. {blq_cli-0.11.2 → blq_cli-1.0.0}/docs/commands/capture.md +1 -1
  6. {blq_cli-0.11.2 → blq_cli-1.0.0}/docs/commands/completions.md +1 -1
  7. {blq_cli-0.11.2 → blq_cli-1.0.0}/docs/commands/exec.md +3 -3
  8. {blq_cli-0.11.2 → blq_cli-1.0.0}/docs/commands/index.md +1 -1
  9. {blq_cli-0.11.2 → blq_cli-1.0.0}/docs/commands/init.md +5 -5
  10. {blq_cli-0.11.2 → blq_cli-1.0.0}/docs/commands/maintenance.md +8 -8
  11. {blq_cli-0.11.2 → blq_cli-1.0.0}/docs/commands/registry.md +6 -6
  12. {blq_cli-0.11.2 → blq_cli-1.0.0}/docs/commands/run.md +3 -3
  13. {blq_cli-0.11.2 → blq_cli-1.0.0}/docs/commands/sql.md +1 -1
  14. {blq_cli-0.11.2 → blq_cli-1.0.0}/docs/commands/sync.md +6 -6
  15. {blq_cli-0.11.2 → blq_cli-1.0.0}/docs/commands/watch.md +1 -1
  16. {blq_cli-0.11.2 → blq_cli-1.0.0}/docs/getting-started.md +1 -1
  17. {blq_cli-0.11.2 → blq_cli-1.0.0}/docs/index.md +5 -2
  18. {blq_cli-0.11.2 → blq_cli-1.0.0}/docs/integration.md +1 -1
  19. {blq_cli-0.11.2 → blq_cli-1.0.0}/docs/mcp.md +2 -2
  20. {blq_cli-0.11.2 → blq_cli-1.0.0}/docs/plans/roadmap-to-1.0.md +2 -2
  21. blq_cli-1.0.0/docs/plugin-guide.md +354 -0
  22. {blq_cli-0.11.2 → blq_cli-1.0.0}/docs/python-api.md +3 -3
  23. {blq_cli-0.11.2 → blq_cli-1.0.0}/docs/sandbox.md +1 -1
  24. blq_cli-1.0.0/docs/schema-stability.md +150 -0
  25. {blq_cli-0.11.2 → blq_cli-1.0.0}/docs/schema.md +3 -3
  26. {blq_cli-0.11.2 → blq_cli-1.0.0}/pyproject.toml +1 -1
  27. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq/bird.py +12 -7
  28. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq/bird_schema.sql +3 -3
  29. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq/cli.py +6 -6
  30. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq/commands/ci_cmd.py +3 -3
  31. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq/commands/clean_cmd.py +4 -4
  32. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq/commands/config_cmd.py +1 -1
  33. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq/commands/core.py +66 -37
  34. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq/commands/execution.py +4 -4
  35. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq/commands/hooks_cmd.py +17 -17
  36. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq/commands/hooks_gen.py +2 -2
  37. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq/commands/init_cmd.py +28 -24
  38. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq/commands/management.py +6 -6
  39. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq/commands/migrate.py +2 -2
  40. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq/commands/query_cmd.py +1 -1
  41. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq/commands/registry.py +1 -1
  42. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq/commands/serve_cmd.py +1 -1
  43. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq/commands/sync_cmd.py +4 -4
  44. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq/locks.py +1 -1
  45. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq/query.py +14 -14
  46. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq/schema.sql +3 -3
  47. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq/serve.py +15 -10
  48. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq/storage.py +22 -14
  49. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq/templates/drone.yml.j2 +1 -1
  50. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq/templates/git_hook.sh.j2 +1 -1
  51. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq/templates/github_workflow.yml.j2 +1 -1
  52. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq/templates/gitlab_ci.yml.j2 +1 -1
  53. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq/templates/hook_script.sh.j2 +1 -1
  54. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq/user_config.py +2 -2
  55. {blq_cli-0.11.2 → blq_cli-1.0.0}/tests/conftest.py +2 -2
  56. {blq_cli-0.11.2 → blq_cli-1.0.0}/tests/test_attempts_outcomes.py +31 -31
  57. {blq_cli-0.11.2 → blq_cli-1.0.0}/tests/test_auto_init.py +3 -3
  58. {blq_cli-0.11.2 → blq_cli-1.0.0}/tests/test_autoprune.py +10 -10
  59. {blq_cli-0.11.2 → blq_cli-1.0.0}/tests/test_bird.py +19 -19
  60. {blq_cli-0.11.2 → blq_cli-1.0.0}/tests/test_ci_generators.py +5 -5
  61. {blq_cli-0.11.2 → blq_cli-1.0.0}/tests/test_core.py +20 -20
  62. {blq_cli-0.11.2 → blq_cli-1.0.0}/tests/test_ext_integration.py +1 -1
  63. {blq_cli-0.11.2 → blq_cli-1.0.0}/tests/test_ext_types.py +3 -3
  64. {blq_cli-0.11.2 → blq_cli-1.0.0}/tests/test_hooks.py +4 -4
  65. {blq_cli-0.11.2 → blq_cli-1.0.0}/tests/test_hooks_gen.py +5 -5
  66. {blq_cli-0.11.2 → blq_cli-1.0.0}/tests/test_inspect.py +4 -4
  67. {blq_cli-0.11.2 → blq_cli-1.0.0}/tests/test_phase2_command_registry.py +4 -4
  68. {blq_cli-0.11.2 → blq_cli-1.0.0}/tests/test_query_api.py +2 -2
  69. {blq_cli-0.11.2 → blq_cli-1.0.0}/tests/test_query_filter.py +3 -3
  70. {blq_cli-0.11.2 → blq_cli-1.0.0}/tests/test_record_invocation.py +7 -7
  71. {blq_cli-0.11.2 → blq_cli-1.0.0}/tests/test_sandbox_ext.py +1 -1
  72. {blq_cli-0.11.2 → blq_cli-1.0.0}/tests/test_storage.py +2 -2
  73. {blq_cli-0.11.2 → blq_cli-1.0.0}/.claude/hooks/blq-suggest.sh +0 -0
  74. {blq_cli-0.11.2 → blq_cli-1.0.0}/.github/workflows/ci.yml +0 -0
  75. {blq_cli-0.11.2 → blq_cli-1.0.0}/.github/workflows/docs.yml +0 -0
  76. {blq_cli-0.11.2 → blq_cli-1.0.0}/.github/workflows/publish.yml +0 -0
  77. {blq_cli-0.11.2 → blq_cli-1.0.0}/.mcp.json +0 -0
  78. {blq_cli-0.11.2 → blq_cli-1.0.0}/.readthedocs.yml +0 -0
  79. {blq_cli-0.11.2 → blq_cli-1.0.0}/AGENT.md +0 -0
  80. {blq_cli-0.11.2 → blq_cli-1.0.0}/AGENTS.md +0 -0
  81. {blq_cli-0.11.2 → blq_cli-1.0.0}/CONTRIBUTING.md +0 -0
  82. {blq_cli-0.11.2 → blq_cli-1.0.0}/README.md +0 -0
  83. {blq_cli-0.11.2 → blq_cli-1.0.0}/SKILL.md +0 -0
  84. {blq_cli-0.11.2 → blq_cli-1.0.0}/docs/commands/ci.md +0 -0
  85. {blq_cli-0.11.2 → blq_cli-1.0.0}/docs/commands/errors.md +0 -0
  86. {blq_cli-0.11.2 → blq_cli-1.0.0}/docs/commands/filter.md +0 -0
  87. {blq_cli-0.11.2 → blq_cli-1.0.0}/docs/commands/query.md +0 -0
  88. {blq_cli-0.11.2 → blq_cli-1.0.0}/docs/commands/report.md +0 -0
  89. {blq_cli-0.11.2 → blq_cli-1.0.0}/docs/commands/status.md +0 -0
  90. {blq_cli-0.11.2 → blq_cli-1.0.0}/docs/design/design-bird-migration.md +0 -0
  91. {blq_cli-0.11.2 → blq_cli-1.0.0}/docs/design/design-commands.md +0 -0
  92. {blq_cli-0.11.2 → blq_cli-1.0.0}/docs/design/design-config-command.md +0 -0
  93. {blq_cli-0.11.2 → blq_cli-1.0.0}/docs/design/design-extensions.md +0 -0
  94. {blq_cli-0.11.2 → blq_cli-1.0.0}/docs/design/design-git-integration.md +0 -0
  95. {blq_cli-0.11.2 → blq_cli-1.0.0}/docs/design/design-hooks-v2.md +0 -0
  96. {blq_cli-0.11.2 → blq_cli-1.0.0}/docs/design/design-live-inspection.md +0 -0
  97. {blq_cli-0.11.2 → blq_cli-1.0.0}/docs/design/design-parameterized-commands.md +0 -0
  98. {blq_cli-0.11.2 → blq_cli-1.0.0}/docs/design/design-run-args.md +0 -0
  99. {blq_cli-0.11.2 → blq_cli-1.0.0}/docs/design/design-sandbox-specs.md +0 -0
  100. {blq_cli-0.11.2 → blq_cli-1.0.0}/docs/design/design-sync.md +0 -0
  101. {blq_cli-0.11.2 → blq_cli-1.0.0}/docs/design/design-track-save.md +0 -0
  102. {blq_cli-0.11.2 → blq_cli-1.0.0}/docs/design/duck-hunt-v2-migration.md +0 -0
  103. {blq_cli-0.11.2 → blq_cli-1.0.0}/docs/design/duck-hunt-v3-migration.md +0 -0
  104. {blq_cli-0.11.2 → blq_cli-1.0.0}/docs/design/proposal-bird-v5.md +0 -0
  105. {blq_cli-0.11.2 → blq_cli-1.0.0}/docs/design/skill-inspect-enrichment.md +0 -0
  106. {blq_cli-0.11.2 → blq_cli-1.0.0}/docs/plans/explore-nsjail-python-wrapper.md +0 -0
  107. {blq_cli-0.11.2 → blq_cli-1.0.0}/docs/plans/explore-nsjail-spack-package.md +0 -0
  108. {blq_cli-0.11.2 → blq_cli-1.0.0}/docs/plans/patterns-integration-prompt.md +0 -0
  109. {blq_cli-0.11.2 → blq_cli-1.0.0}/docs/query-guide.md +0 -0
  110. {blq_cli-0.11.2 → blq_cli-1.0.0}/docs/requirements.txt +0 -0
  111. {blq_cli-0.11.2 → blq_cli-1.0.0}/docs/superpowers/plans/2026-03-22-extension-system.md +0 -0
  112. {blq_cli-0.11.2 → blq_cli-1.0.0}/docs/superpowers/plans/2026-03-28-bwrap-engine.md +0 -0
  113. {blq_cli-0.11.2 → blq_cli-1.0.0}/docs/superpowers/plans/2026-03-28-command-locks.md +0 -0
  114. {blq_cli-0.11.2 → blq_cli-1.0.0}/docs/superpowers/plans/2026-03-29-annotators-and-tighten.md +0 -0
  115. {blq_cli-0.11.2 → blq_cli-1.0.0}/docs/superpowers/plans/2026-03-29-service-layer-phase1.md +0 -0
  116. {blq_cli-0.11.2 → blq_cli-1.0.0}/docs/superpowers/plans/2026-03-29-strace-profiling.md +0 -0
  117. {blq_cli-0.11.2 → blq_cli-1.0.0}/docs/superpowers/specs/2026-03-22-extension-system-design.md +0 -0
  118. {blq_cli-0.11.2 → blq_cli-1.0.0}/docs/superpowers/specs/2026-03-29-unified-service-layer-design.md +0 -0
  119. {blq_cli-0.11.2 → blq_cli-1.0.0}/experiments/agent-build-test.md +0 -0
  120. {blq_cli-0.11.2 → blq_cli-1.0.0}/mkdocs.yml +0 -0
  121. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq/__init__.py +0 -0
  122. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq/__main__.py +0 -0
  123. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq/commands/README.md +0 -0
  124. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq/commands/__init__.py +0 -0
  125. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq/commands/events.py +0 -0
  126. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq/commands/management_cmd.py +0 -0
  127. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq/commands/mcp_cmd.py +0 -0
  128. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq/commands/record_cmd.py +0 -0
  129. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq/commands/report_cmd.py +0 -0
  130. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq/commands/sandbox_cmd.py +0 -0
  131. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq/commands/watch_cmd.py +0 -0
  132. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq/config_format.py +0 -0
  133. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq/ext/__init__.py +0 -0
  134. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq/ext/annotator.py +0 -0
  135. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq/ext/discovery.py +0 -0
  136. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq/ext/local_executor.py +0 -0
  137. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq/ext/pipeline.py +0 -0
  138. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq/git.py +0 -0
  139. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq/github.py +0 -0
  140. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq/output.py +0 -0
  141. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq/services/__init__.py +0 -0
  142. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq/services/execution.py +0 -0
  143. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq/services/inspect.py +0 -0
  144. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq/services/query.py +0 -0
  145. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq/services/refs.py +0 -0
  146. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq_sandbox/__init__.py +0 -0
  147. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq_sandbox/engines.py +0 -0
  148. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq_sandbox/profile.py +0 -0
  149. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq_sandbox/source_annotator.py +0 -0
  150. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq_sandbox/spec.py +0 -0
  151. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq_sandbox/strace_parser.py +0 -0
  152. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq_sandbox/tighten.py +0 -0
  153. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq_sandbox/violations.py +0 -0
  154. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq_sandbox_bwrap/__init__.py +0 -0
  155. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq_sandbox_bwrap/args.py +0 -0
  156. {blq_cli-0.11.2 → blq_cli-1.0.0}/src/blq_sandbox_systemd/__init__.py +0 -0
  157. {blq_cli-0.11.2 → blq_cli-1.0.0}/tests/__init__.py +0 -0
  158. {blq_cli-0.11.2 → blq_cli-1.0.0}/tests/sql/test_duck_hunt_v2_migration.sql +0 -0
  159. {blq_cli-0.11.2 → blq_cli-1.0.0}/tests/test_annotator.py +0 -0
  160. {blq_cli-0.11.2 → blq_cli-1.0.0}/tests/test_bwrap_args.py +0 -0
  161. {blq_cli-0.11.2 → blq_cli-1.0.0}/tests/test_bwrap_engine.py +0 -0
  162. {blq_cli-0.11.2 → blq_cli-1.0.0}/tests/test_ci.py +0 -0
  163. {blq_cli-0.11.2 → blq_cli-1.0.0}/tests/test_command_args.py +0 -0
  164. {blq_cli-0.11.2 → blq_cli-1.0.0}/tests/test_command_lock_field.py +0 -0
  165. {blq_cli-0.11.2 → blq_cli-1.0.0}/tests/test_execution_locks.py +0 -0
  166. {blq_cli-0.11.2 → blq_cli-1.0.0}/tests/test_exit_code_reason.py +0 -0
  167. {blq_cli-0.11.2 → blq_cli-1.0.0}/tests/test_ext_discovery.py +0 -0
  168. {blq_cli-0.11.2 → blq_cli-1.0.0}/tests/test_ext_local_executor.py +0 -0
  169. {blq_cli-0.11.2 → blq_cli-1.0.0}/tests/test_ext_pipeline.py +0 -0
  170. {blq_cli-0.11.2 → blq_cli-1.0.0}/tests/test_git.py +0 -0
  171. {blq_cli-0.11.2 → blq_cli-1.0.0}/tests/test_json_null_filter.py +0 -0
  172. {blq_cli-0.11.2 → blq_cli-1.0.0}/tests/test_locks.py +0 -0
  173. {blq_cli-0.11.2 → blq_cli-1.0.0}/tests/test_mcp_ci_tools.py +0 -0
  174. {blq_cli-0.11.2 → blq_cli-1.0.0}/tests/test_mcp_merge.py +0 -0
  175. {blq_cli-0.11.2 → blq_cli-1.0.0}/tests/test_mcp_server.py +0 -0
  176. {blq_cli-0.11.2 → blq_cli-1.0.0}/tests/test_phase1_structured_output.py +0 -0
  177. {blq_cli-0.11.2 → blq_cli-1.0.0}/tests/test_report.py +0 -0
  178. {blq_cli-0.11.2 → blq_cli-1.0.0}/tests/test_sandbox.py +0 -0
  179. {blq_cli-0.11.2 → blq_cli-1.0.0}/tests/test_sandbox_cmd.py +0 -0
  180. {blq_cli-0.11.2 → blq_cli-1.0.0}/tests/test_sandbox_events.py +0 -0
  181. {blq_cli-0.11.2 → blq_cli-1.0.0}/tests/test_sandbox_profile.py +0 -0
  182. {blq_cli-0.11.2 → blq_cli-1.0.0}/tests/test_sandbox_register.py +0 -0
  183. {blq_cli-0.11.2 → blq_cli-1.0.0}/tests/test_sandbox_systemd.py +0 -0
  184. {blq_cli-0.11.2 → blq_cli-1.0.0}/tests/test_sandbox_tighten.py +0 -0
  185. {blq_cli-0.11.2 → blq_cli-1.0.0}/tests/test_sandbox_violations.py +0 -0
  186. {blq_cli-0.11.2 → blq_cli-1.0.0}/tests/test_services_execution.py +0 -0
  187. {blq_cli-0.11.2 → blq_cli-1.0.0}/tests/test_services_inspect.py +0 -0
  188. {blq_cli-0.11.2 → blq_cli-1.0.0}/tests/test_services_query.py +0 -0
  189. {blq_cli-0.11.2 → blq_cli-1.0.0}/tests/test_services_refs.py +0 -0
  190. {blq_cli-0.11.2 → blq_cli-1.0.0}/tests/test_source_annotator.py +0 -0
  191. {blq_cli-0.11.2 → blq_cli-1.0.0}/tests/test_storage_prune.py +0 -0
  192. {blq_cli-0.11.2 → blq_cli-1.0.0}/tests/test_strace_parser.py +0 -0
  193. {blq_cli-0.11.2 → blq_cli-1.0.0}/tests/test_user_config.py +0 -0
  194. {blq_cli-0.11.2 → blq_cli-1.0.0}/tests/test_watch.py +0 -0
@@ -41,7 +41,8 @@ htmlcov/
41
41
  # mypy
42
42
  .mypy_cache/
43
43
 
44
- # lq data (local to each project)
44
+ # BIRD data (local to each project)
45
+ .bird/
45
46
  .lq/
46
47
 
47
48
  # Documentation
@@ -98,7 +98,7 @@ This is the initial scaffolding for `blq` (Build Log Query) - a CLI tool for cap
98
98
  - [ ] Consider integration with duckdb_mcp for ATTACH/DETACH workflow
99
99
 
100
100
  **BIRD Spec:**
101
- - [ ] Migrate from `.lq/` to `.bird/` directory (pending spec finalization)
101
+ - [x] Migrated from `.lq/` to `.bird/` directory (auto-migration from legacy)
102
102
  - [ ] Running process tracking (pending BIRD spec)
103
103
  - [ ] Migrate to updated BIRD spec (when ready)
104
104
 
@@ -111,13 +111,13 @@ This is the initial scaffolding for `blq` (Build Log Query) - a CLI tool for cap
111
111
  ```
112
112
  blq (Python CLI)
113
113
 
114
- ├── .lq/blq.duckdb - BIRD database with tables and macros
114
+ ├── .bird/blq.duckdb - BIRD database with tables and macros
115
115
  │ ├── sessions - Invoker sessions (shell, CLI, MCP)
116
116
  │ ├── invocations - Command executions with metadata
117
117
  │ ├── outputs - Captured stdout/stderr (content-addressed)
118
118
  │ └── events - Parsed diagnostics (errors, warnings)
119
119
 
120
- ├── .lq/blobs/ - Content-addressed blob storage
120
+ ├── .bird/blobs/ - Content-addressed blob storage
121
121
  │ └── content/ab/{hash}.bin
122
122
 
123
123
  ├── Uses duckdb Python API directly
@@ -171,7 +171,7 @@ All SQL macros use the `blq_` prefix:
171
171
 
172
172
  Direct DuckDB access:
173
173
  ```bash
174
- duckdb .lq/blq.duckdb "SELECT * FROM blq_status()"
174
+ duckdb .bird/blq.duckdb "SELECT * FROM blq_status()"
175
175
  ```
176
176
 
177
177
  ## Run Metadata
@@ -193,7 +193,7 @@ Each `blq run` captures comprehensive execution context:
193
193
 
194
194
  ### Environment Capture
195
195
 
196
- Configurable in `.lq/config.toml`:
196
+ Configurable in `.bird/config.toml`:
197
197
  ```toml
198
198
  capture_env = [
199
199
  "PATH",
@@ -221,7 +221,7 @@ SELECT ci['provider'], ci['run_id'] FROM blq_load_events() WHERE ci IS NOT NULL
221
221
 
222
222
  ## Project Identification
223
223
 
224
- Detected at `blq init` and stored in `.lq/config.toml`:
224
+ Detected at `blq init` and stored in `.bird/config.toml`:
225
225
 
226
226
  ```toml
227
227
  [project]
@@ -265,7 +265,7 @@ Runtime override: `blq run --no-capture <cmd>` or `blq run --capture <cmd>`
265
265
 
266
266
  1. **BIRD as default storage**: DuckDB tables for simpler queries, content-addressed blobs for outputs
267
267
  2. **Parquet mode available**: For multi-writer scenarios (legacy, use `--parquet` flag)
268
- 3. **Project-local storage**: `.lq/` directory in project root
268
+ 3. **Project-local storage**: `.bird/` directory in project root
269
269
  4. **blq.duckdb for everything**: Tables, views, and macros in single database file
270
270
  5. **Table-returning macros**: `blq_load_events()` evaluated at query time, not view creation
271
271
  6. **Backward-compatible views**: `blq_events_flat` provides v1-compatible schema
@@ -334,7 +334,7 @@ blq mcp serve -D exec,clean # Disable specific tools
334
334
  blq mcp serve -S -D custom_tool # Combine safe mode with additional tools
335
335
  ```
336
336
 
337
- Or via `.lq/config.toml`:
337
+ Or via `.bird/config.toml`:
338
338
  ```toml
339
339
  [mcp]
340
340
  disabled_tools = ["clean", "register_command", "unregister_command"]
@@ -441,7 +441,7 @@ ruff format src/blq/
441
441
 
442
442
  ### Config Options
443
443
 
444
- Key `.lq/config.toml` options:
444
+ Key `.bird/config.toml` options:
445
445
  ```toml
446
446
  [storage]
447
447
  keep_raw = true # Always keep raw output
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: blq-cli
3
- Version: 0.11.2
3
+ Version: 1.0.0
4
4
  Summary: Buidl Log Query - capture and query build/test logs with DuckDB
5
5
  Project-URL: Homepage, https://blq-cli.readthedocs.com/
6
6
  Project-URL: Repository, https://github.com/teaguesterling/blq-cli
@@ -0,0 +1,601 @@
1
+ # API Reference
2
+
3
+ Complete reference for blq's Python API and MCP tool schemas. For tutorial-style usage, see [Python API Guide](python-api.md) and [MCP Guide](mcp.md).
4
+
5
+ Source files: [`src/blq/query.py`](../src/blq/query.py), [`src/blq/storage.py`](../src/blq/storage.py), [`src/blq/services/`](../src/blq/services/), [`src/blq/serve.py`](../src/blq/serve.py)
6
+
7
+ ---
8
+
9
+ ## BlqStorage
10
+
11
+ **Module:** `blq.storage`
12
+
13
+ Low-level storage interface backed by BIRD (DuckDB tables + content-addressed blobs). Query methods return `DuckDBPyRelation` objects -- call `.df()` for DataFrame or `.fetchall()` for tuples.
14
+
15
+ ### Construction
16
+
17
+ ```python
18
+ from blq.storage import BlqStorage
19
+
20
+ storage = BlqStorage.open() # auto-find .bird from cwd
21
+ storage = BlqStorage.open("/path/to/.bird") # explicit path
22
+ ```
23
+
24
+ Supports context manager:
25
+
26
+ ```python
27
+ with BlqStorage.open() as storage:
28
+ errors = storage.errors().df()
29
+ ```
30
+
31
+ ### Properties
32
+
33
+ | Property | Type | Description |
34
+ |----------|------|-------------|
35
+ | `path` | `Path` | Path to `.bird` directory |
36
+ | `connection` | `duckdb.DuckDBPyConnection` | Underlying DuckDB connection |
37
+
38
+ ### Data Checks
39
+
40
+ ```python
41
+ storage.has_data() -> bool # any runs exist
42
+ storage.has_runs() -> bool # alias for has_data()
43
+ storage.has_events() -> bool # any parsed events exist
44
+ ```
45
+
46
+ ### Run Queries
47
+
48
+ ```python
49
+ storage.runs(limit: int | None = None) -> DuckDBPyRelation
50
+ ```
51
+ All runs with aggregated event counts, newest first. Columns: `run_id`, `source_name`, `source_type`, `command`, `tag`, `started_at`, `completed_at`, `exit_code`, `cwd`, `executable_path`, `hostname`, `platform`, `arch`, `git_commit`, `git_branch`, `git_dirty`, `ci`, `event_count`, `error_count`, `warning_count`.
52
+
53
+ ```python
54
+ storage.run(run_id: int) -> DuckDBPyRelation
55
+ storage.latest_run_id() -> int | None
56
+ ```
57
+
58
+ ### Event Queries
59
+
60
+ ```python
61
+ storage.events(
62
+ run_id: int | None = None,
63
+ severity: str | list[str] | None = None,
64
+ limit: int | None = None,
65
+ ) -> DuckDBPyRelation
66
+ ```
67
+
68
+ ```python
69
+ storage.errors(run_id: int | None = None, limit: int = 20) -> DuckDBPyRelation
70
+ storage.warnings(run_id: int | None = None, limit: int = 20) -> DuckDBPyRelation
71
+ storage.event(run_serial: int, event_id: int) -> dict[str, Any] | None
72
+ storage.error_count(run_id: int | None = None) -> int
73
+ storage.warning_count(run_id: int | None = None) -> int
74
+ ```
75
+
76
+ ### Status
77
+
78
+ ```python
79
+ storage.status() -> DuckDBPyRelation # blq_status() summary
80
+ storage.source_status() -> DuckDBPyRelation # per-source latest run
81
+ ```
82
+
83
+ ### Output
84
+
85
+ ```python
86
+ storage.get_output(run_id: str | int, stream: str | None = None) -> bytes | None
87
+ storage.get_output_info(run_id: str | int) -> list[dict[str, Any]]
88
+ ```
89
+ `stream` accepts `'stdout'`, `'stderr'`, `'combined'`, or `None` (any).
90
+
91
+ ### SQL
92
+
93
+ ```python
94
+ storage.sql(query: str, params: list | None = None)
95
+ -> DuckDBPyRelation | DuckDBPyConnection
96
+ ```
97
+ Without `params`, returns a relation. With `params` (using `?` placeholders), returns a connection result. Both support `.fetchall()` and `.fetchone()`.
98
+
99
+ ```python
100
+ storage.sql("SELECT * FROM blq_load_events() WHERE fingerprint = ?", [fp])
101
+ ```
102
+
103
+ ### Write Operations
104
+
105
+ ```python
106
+ storage.write_run(
107
+ run_meta: dict[str, Any],
108
+ events: list[dict[str, Any]] | None = None,
109
+ output: bytes | None = None,
110
+ ) -> str # returns invocation UUID
111
+ ```
112
+
113
+ `run_meta` keys: `command`, `source_name`, `source_type`, `exit_code`, `started_at`, `completed_at`, `cwd`, `hostname`, `platform`, `arch`, `git_commit`, `git_branch`, `git_dirty`, `ci`, `environment`.
114
+
115
+ ### Maintenance
116
+
117
+ ```python
118
+ storage.prune(days: int = 30) -> int # remove old data
119
+ storage.prune_by_max_runs(max_runs: int) -> int # keep N per source
120
+ storage.prune_by_size(max_size_mb: int) -> int # cap total output size
121
+ storage.cleanup_blobs() -> tuple[int, int] # (deleted, bytes_freed)
122
+ storage.total_output_size() -> int # total bytes
123
+ ```
124
+
125
+ ---
126
+
127
+ ## LogStore
128
+
129
+ **Module:** `blq.query`
130
+
131
+ Higher-level query API with fluent `LogQuery` builder. Returns pandas DataFrames.
132
+
133
+ ### Construction
134
+
135
+ ```python
136
+ from blq.query import LogStore
137
+
138
+ store = LogStore.open() # auto-find .bird
139
+ store = LogStore.open("/path/to/.bird") # explicit path
140
+ store = LogStore("/path/to/.bird") # direct init
141
+ store = LogStore.from_parquet_root("path") # raw parquet directory
142
+ ```
143
+
144
+ ### Properties
145
+
146
+ | Property | Type | Description |
147
+ |----------|------|-------------|
148
+ | `path` | `Path` | `.bird` directory path |
149
+ | `logs_path` | `Path` | Logs subdirectory path |
150
+ | `connection` | `duckdb.DuckDBPyConnection` | DuckDB connection |
151
+
152
+ ### Query Methods
153
+
154
+ ```python
155
+ store.events() -> LogQuery # all events
156
+ store.errors() -> LogQuery # severity='error'
157
+ store.warnings() -> LogQuery # severity='warning'
158
+ store.run(run_id: int) -> LogQuery # events from one run
159
+ store.runs() -> pd.DataFrame # run summaries
160
+ store.latest_run() -> int | None # most recent run_id
161
+ store.event(run_id: int, event_id: int) -> dict[str, Any] | None
162
+ store.has_data() -> bool
163
+ ```
164
+
165
+ ---
166
+
167
+ ## LogQuery
168
+
169
+ **Module:** `blq.query`
170
+
171
+ Fluent query builder wrapping a DuckDB relation. All operations are deferred until a terminal method is called.
172
+
173
+ ### Construction
174
+
175
+ ```python
176
+ from blq.query import LogQuery
177
+
178
+ LogQuery.from_file(path, format="auto", conn=None) -> LogQuery
179
+ LogQuery.from_content(content: str, format="auto", conn=None) -> LogQuery
180
+ LogQuery.from_sql(conn, sql, params=None) -> LogQuery
181
+ LogQuery.from_table(conn, table_name) -> LogQuery
182
+ LogQuery.from_parquet(path, conn=None, hive_partitioning=True) -> LogQuery
183
+ LogQuery.from_relation(rel, conn) -> LogQuery
184
+ ```
185
+
186
+ ### Filtering
187
+
188
+ ```python
189
+ .filter(severity="error") # exact match
190
+ .filter(severity=["error", "warning"]) # IN clause
191
+ .filter(ref_file="%main%") # ILIKE pattern
192
+ .filter(severity="!info") # NOT equal
193
+ .filter(ref_line=100) # numeric equality
194
+ .filter(severity=None) # IS NULL
195
+ .filter("ref_line > 100") # raw SQL condition
196
+ .exclude(severity="info") # NOT (severity = 'info')
197
+ .where("ref_line BETWEEN 10 AND 50") # raw SQL WHERE
198
+ ```
199
+
200
+ ### Projection
201
+
202
+ ```python
203
+ .select(*columns: str) -> LogQuery
204
+ .order_by(*columns: str, desc: bool = False) -> LogQuery
205
+ .limit(n: int) -> LogQuery
206
+ ```
207
+
208
+ ### Terminal Methods
209
+
210
+ ```python
211
+ .df() -> pd.DataFrame
212
+ .fetchall() -> list[tuple]
213
+ .fetchone() -> tuple | None
214
+ .count() -> int
215
+ .exists() -> bool
216
+ .show(n: int = 10) -> None # print to stdout
217
+ .explain() -> str # query plan
218
+ .describe() -> pd.DataFrame # statistics
219
+ ```
220
+
221
+ ### Inspection
222
+
223
+ ```python
224
+ .columns -> list[str]
225
+ .dtypes -> list[str]
226
+ ```
227
+
228
+ ### Aggregation
229
+
230
+ ```python
231
+ .group_by(*columns) -> LogQueryGrouped
232
+ .value_counts(column: str) -> pd.DataFrame
233
+ ```
234
+
235
+ ---
236
+
237
+ ## LogQueryGrouped
238
+
239
+ **Module:** `blq.query`
240
+
241
+ Returned by `LogQuery.group_by()`. All methods return `pd.DataFrame`.
242
+
243
+ ```python
244
+ grouped = query.group_by("ref_file")
245
+ grouped.count() -> pd.DataFrame
246
+ grouped.sum(column: str) -> pd.DataFrame
247
+ grouped.avg(column: str) -> pd.DataFrame
248
+ grouped.min(column: str) -> pd.DataFrame
249
+ grouped.max(column: str) -> pd.DataFrame
250
+ grouped.agg(**aggregations: str) -> pd.DataFrame
251
+ ```
252
+
253
+ `agg` example: `.agg(total="COUNT(*)", first_line="MIN(ref_line)")`
254
+
255
+ ---
256
+
257
+ ## Service Layer
258
+
259
+ **Module:** `blq.services`
260
+
261
+ Pure business logic shared by CLI and MCP. All query functions take `BlqStorage` as the first argument and return structured dicts/lists.
262
+
263
+ ### Refs
264
+
265
+ ```python
266
+ from blq.services import parse_ref, resolve_run_ref, ParsedRef
267
+ ```
268
+
269
+ ```python
270
+ parse_ref(ref: str) -> ParsedRef
271
+ ```
272
+ Parses ref strings into structured form. Raises `ValueError` on invalid input.
273
+
274
+ | Input | Result |
275
+ |-------|--------|
276
+ | `"5"` | `ParsedRef(run_serial=5)` |
277
+ | `"build:3"` | `ParsedRef(tag="build", run_serial=3)` |
278
+ | `"test:5:2"` | `ParsedRef(tag="test", run_serial=5, event_id=2)` |
279
+ | `"5:2"` | `ParsedRef(run_serial=5, event_id=2)` |
280
+ | `"~1"` | `ParsedRef(relative=1)` |
281
+ | `"test:~2"` | `ParsedRef(tag="test", relative=2)` |
282
+ | UUID | `ParsedRef(uuid="...")` |
283
+
284
+ `ParsedRef` properties: `is_relative -> bool`, `run_ref -> str`.
285
+
286
+ ```python
287
+ resolve_run_ref(storage: BlqStorage, ref: str) -> dict | None
288
+ ```
289
+ Resolves a ref string to a run data dict. Returns `None` if not found.
290
+
291
+ ### Queries
292
+
293
+ ```python
294
+ from blq.services import query_status, query_history, query_events, query_diff
295
+ ```
296
+
297
+ ```python
298
+ query_status(storage: BlqStorage) -> list[dict[str, Any]]
299
+ ```
300
+ Returns per-source status: `name`, `status`, `error_count`, `warning_count`, `last_run`, `run_ref`, `run_serial`.
301
+
302
+ ```python
303
+ query_history(
304
+ storage: BlqStorage,
305
+ limit: int = 20,
306
+ source: str | None = None,
307
+ status: str | None = None, # 'running', 'completed', 'orphaned'
308
+ ) -> list[dict[str, Any]]
309
+ ```
310
+ Returns: `run_ref`, `run_serial`, `source_name`, `status`, `error_count`, `warning_count`, `started_at`, `exit_code`, `command`, `git_commit`, `git_branch`, `git_dirty`.
311
+
312
+ ```python
313
+ query_events(
314
+ storage: BlqStorage,
315
+ severity: str | None = None, # 'error', 'warning', or comma-separated
316
+ run_id: int | None = None,
317
+ source: str | None = None,
318
+ file_pattern: str | None = None,
319
+ limit: int = 20,
320
+ default_to_latest: bool = False,
321
+ suppressed_fingerprints: list[str] | None = None,
322
+ all_runs: bool = False,
323
+ ) -> dict[str, Any] # {"events": [...], "total_count": int}
324
+ ```
325
+
326
+ ```python
327
+ query_diff(storage: BlqStorage, run1: int, run2: int) -> dict[str, Any]
328
+ ```
329
+ Returns: `summary` (`run1_errors`, `run2_errors`, `fixed`, `new`, `unchanged`), `fixed` (list), `new` (list).
330
+
331
+ ### Inspect
332
+
333
+ ```python
334
+ from blq.services import (
335
+ get_source_context, get_log_context,
336
+ get_git_context, get_fingerprint_history,
337
+ )
338
+ ```
339
+
340
+ ```python
341
+ get_source_context(
342
+ ref_file: str | None, ref_line: int | None,
343
+ source_root: Path, context_lines: int = 3,
344
+ ) -> str | None
345
+
346
+ get_log_context(
347
+ storage: BlqStorage | None, run_id: int,
348
+ log_line_start: int | None, log_line_end: int | None,
349
+ context_lines: int = 3,
350
+ ) -> str | None
351
+
352
+ get_git_context(
353
+ ref_file: str | None, ref_line: int | None,
354
+ source_root: Path, history_limit: int = 2,
355
+ ) -> dict[str, Any] | None # {file, line, blame, recent_commits}
356
+
357
+ get_fingerprint_history(
358
+ storage: BlqStorage | None, fingerprint: str | None,
359
+ ) -> dict[str, Any] | None # {fingerprint, first_seen, last_seen, occurrences, is_regression}
360
+ ```
361
+
362
+ ### Execution
363
+
364
+ ```python
365
+ from blq.services import run_result_to_concise
366
+
367
+ run_result_to_concise(full_result: dict[str, Any], source_name: str) -> dict[str, Any]
368
+ ```
369
+ Converts a `RunResult.to_json()` dict into the concise response format with keys: `run_ref`, `cmd`, `status`, `exit_code`, `duration_sec`, `summary`, `output_stats`. Conditionally includes `errors` (max 10), `warnings` (max 5), `infos` (max 5).
370
+
371
+ ---
372
+
373
+ ## MCP Tools
374
+
375
+ MCP server started via `blq mcp serve`. Tools are callable by any MCP client.
376
+
377
+ ### run
378
+
379
+ Run a registered command and capture output.
380
+
381
+ | Parameter | Type | Default | Description |
382
+ |-----------|------|---------|-------------|
383
+ | `command` | `str` | required | Registered command name |
384
+ | `args` | `dict[str,str] \| list[str] \| None` | `None` | Named args (dict) or positional args (list) |
385
+ | `extra` | `list[str] \| None` | `None` | Passthrough arguments appended to command |
386
+ | `timeout` | `int \| None` | `None` | Timeout in seconds |
387
+ | `lines` | `str \| None` | `None` | Line selection for inline output (e.g. `'+20-'`) |
388
+ | `commands` | `list[str] \| None` | `None` | Batch mode: run multiple commands in sequence |
389
+ | `stop_on_failure` | `bool` | `True` | Stop batch on first failure |
390
+
391
+ **Returns:** `{run_ref, cmd, status, exit_code, duration_sec, summary, output_stats, errors?, warnings?}`
392
+
393
+ ### exec
394
+
395
+ Execute an ad-hoc shell command. Do not use pipes/redirects -- use `output()` tool instead.
396
+
397
+ | Parameter | Type | Default | Description |
398
+ |-----------|------|---------|-------------|
399
+ | `command` | `str` | required | Shell command (no pipes) |
400
+ | `args` | `list[str] \| None` | `None` | Additional arguments |
401
+ | `timeout` | `int \| None` | `None` | Timeout in seconds |
402
+ | `shell` | `bool` | `False` | Allow shell syntax |
403
+ | `lines` | `str \| None` | `None` | Inline output line selection |
404
+
405
+ **Returns:** Same shape as `run`.
406
+
407
+ ### status
408
+
409
+ No parameters. Returns `{sources: [{name, status, error_count, warning_count, last_run, run_ref}]}`.
410
+
411
+ ### events
412
+
413
+ | Parameter | Type | Default | Description |
414
+ |-----------|------|---------|-------------|
415
+ | `limit` | `int` | `20` | Max events |
416
+ | `run_id` | `int \| None` | `None` | Filter by run serial |
417
+ | `source` | `str \| None` | `None` | Filter by source name |
418
+ | `severity` | `str \| None` | `None` | `'error'`, `'warning'`, or comma-separated |
419
+ | `file_pattern` | `str \| None` | `None` | SQL LIKE pattern for `ref_file` |
420
+ | `all_runs` | `bool` | `False` | Show all runs (default: most recent only) |
421
+ | `run_ids` | `list[int] \| None` | `None` | Batch mode: multiple run IDs |
422
+ | `limit_per_run` | `int` | `10` | Max events per run in batch mode |
423
+
424
+ **Returns:** `{events: [...], total_count: int}`
425
+
426
+ ### inspect
427
+
428
+ | Parameter | Type | Default | Description |
429
+ |-----------|------|---------|-------------|
430
+ | `ref` | `str` | required | Event ref (e.g. `"build:1:3"`) |
431
+ | `lines` | `int` | `5` | Context lines before/after |
432
+ | `include_log_context` | `bool` | `True` | Include log output context |
433
+ | `include_source_context` | `bool` | `True` | Include source file context |
434
+ | `include_git_context` | `bool` | `False` | Include git blame/history |
435
+ | `include_fingerprint_history` | `bool` | `False` | Include occurrence history |
436
+ | `refs` | `list[str] \| None` | `None` | Batch mode: multiple refs |
437
+
438
+ **Returns:** `{ref, severity, ref_file, ref_line, message, log_context?, source_context?, git_context?, fingerprint_history?}`
439
+
440
+ ### info
441
+
442
+ | Parameter | Type | Default | Description |
443
+ |-----------|------|---------|-------------|
444
+ | `ref` | `str \| None` | `None` | Run ref or UUID. `None` = most recent |
445
+ | `head` | `int \| None` | `None` | First N lines of output |
446
+ | `tail` | `int \| None` | `None` | Last N lines of output |
447
+ | `errors` | `bool` | `False` | Include error events |
448
+ | `warnings` | `bool` | `False` | Include warning events |
449
+ | `severity` | `str \| None` | `None` | Filter events by severity |
450
+ | `limit` | `int` | `20` | Max events |
451
+ | `context` | `int \| None` | `None` | Log context lines around each event |
452
+
453
+ **Returns:** `{run_ref, status, exit_code, command, started_at, events?, output?, summary?}`
454
+
455
+ ### history
456
+
457
+ | Parameter | Type | Default | Description |
458
+ |-----------|------|---------|-------------|
459
+ | `limit` | `int` | `20` | Max runs |
460
+ | `source` | `str \| None` | `None` | Filter by source name |
461
+ | `status` | `str \| None` | `None` | `'running'`, `'completed'`, `'orphaned'` |
462
+
463
+ **Returns:** `{runs: [...]}`
464
+
465
+ ### query
466
+
467
+ | Parameter | Type | Default | Description |
468
+ |-----------|------|---------|-------------|
469
+ | `sql` | `str \| None` | `None` | Raw SQL query |
470
+ | `filter` | `str \| None` | `None` | Filter expression (e.g. `"severity=error ref_file~test"`) |
471
+ | `limit` | `int` | `100` | Max rows |
472
+
473
+ Filter syntax: `key=value` (exact), `key=v1,v2` (IN), `key~pattern` (ILIKE), `key!=value` (not equal). Space-separated filters are AND'd.
474
+
475
+ **Returns:** `{columns, rows, row_count}`
476
+
477
+ ### output
478
+
479
+ | Parameter | Type | Default | Description |
480
+ |-----------|------|---------|-------------|
481
+ | `ref` | `str` | required | Run ref (e.g. `'5'`, `'test:3'`, `'+1'`) |
482
+ | `stream` | `str \| None` | `None` | `'stdout'`, `'stderr'`, `'combined'` |
483
+ | `tail` | `int \| None` | `None` | Last N lines |
484
+ | `head` | `int \| None` | `None` | First N lines |
485
+ | `grep` | `str \| None` | `None` | Regex search pattern |
486
+ | `context` | `int` | `0` | Context lines around grep matches |
487
+ | `lines` | `str \| None` | `None` | Line spec (e.g. `'100-200'`) |
488
+ | `debug_formats` | `bool` | `False` | Show format detection info |
489
+
490
+ **Returns:** `{output, byte_length, total_lines, ...}`
491
+
492
+ ### diff
493
+
494
+ | Parameter | Type | Default | Description |
495
+ |-----------|------|---------|-------------|
496
+ | `run1` | `int` | required | Baseline run serial |
497
+ | `run2` | `int` | required | Comparison run serial |
498
+
499
+ **Returns:** `{summary: {run1_errors, run2_errors, fixed, new, unchanged}, fixed: [...], new: [...]}`
500
+
501
+ ### commands
502
+
503
+ No parameters. Returns `{commands: [{name, cmd, description, ...}]}`.
504
+
505
+ ### register_command
506
+
507
+ | Parameter | Type | Default | Description |
508
+ |-----------|------|---------|-------------|
509
+ | `name` | `str` | required | Command name |
510
+ | `cmd` | `str \| None` | `None` | Command string |
511
+ | `tpl` | `str \| None` | `None` | Template with `{param}` placeholders |
512
+ | `defaults` | `dict[str,str] \| None` | `None` | Default template parameter values |
513
+ | `description` | `str` | `""` | Description |
514
+ | `timeout` | `int \| None` | `None` | Timeout in seconds |
515
+ | `capture` | `bool` | `True` | Capture and parse output |
516
+ | `force` | `bool` | `False` | Overwrite existing |
517
+ | `format` | `str \| None` | `None` | Log format hint |
518
+ | `run_now` | `bool` | `False` | Run immediately after registering |
519
+ | `lines` | `str \| None` | `None` | Default output line selection |
520
+ | `sandbox` | `str \| dict \| None` | `None` | Sandbox preset or spec dict |
521
+ | `lock` | `str \| None` | `None` | Lock name for concurrency control |
522
+
523
+ **Returns:** `{success, command, run?}`
524
+
525
+ ### unregister_command
526
+
527
+ | Parameter | Type | Default |
528
+ |-----------|------|---------|
529
+ | `name` | `str` | required |
530
+
531
+ **Returns:** `{success: bool}`
532
+
533
+ ### clean
534
+
535
+ | Parameter | Type | Default | Description |
536
+ |-----------|------|---------|-------------|
537
+ | `mode` | `str` | `"data"` | `'data'`, `'prune'`, `'schema'`, `'full'` |
538
+ | `confirm` | `bool` | `False` | Must be `True` to proceed |
539
+ | `days` | `int \| None` | `None` | Prune: remove older than N days |
540
+ | `max_runs` | `int \| None` | `None` | Prune: keep N per source |
541
+ | `max_size_mb` | `int \| None` | `None` | Prune: cap total output size |
542
+
543
+ **Returns:** `{success, message, mode}`
544
+
545
+ ### report
546
+
547
+ | Parameter | Type | Default | Description |
548
+ |-----------|------|---------|-------------|
549
+ | `ref` | `str \| None` | `None` | Run ref (default: latest) |
550
+ | `baseline` | `str \| None` | `None` | Baseline run, branch, or commit |
551
+ | `warnings` | `bool` | `False` | Include warnings |
552
+ | `summary_only` | `bool` | `False` | Omit individual error details |
553
+ | `error_limit` | `int` | `20` | Max errors in details |
554
+ | `file_limit` | `int` | `10` | Max files in breakdown |
555
+
556
+ **Returns:** `{report: "markdown...", run_id, total_errors, total_warnings, has_baseline}`
557
+
558
+ ### ci_check
559
+
560
+ | Parameter | Type | Default | Description |
561
+ |-----------|------|---------|-------------|
562
+ | `baseline` | `str \| None` | `None` | Baseline (auto-detects main/master) |
563
+ | `fail_on_any` | `bool` | `False` | Fail on any errors |
564
+ | `run_id` | `int \| None` | `None` | Run to check (default: auto-detect) |
565
+
566
+ **Returns:** `{status: 'OK'|'FAIL', current_run_id, new_errors?, fixed?}`
567
+
568
+ ### ci_generate
569
+
570
+ | Parameter | Type | Default | Description |
571
+ |-----------|------|---------|-------------|
572
+ | `commands` | `list[str] \| None` | `None` | Commands to generate (default: all) |
573
+ | `shell` | `str` | `"bash"` | `'bash'`, `'sh'`, `'zsh'` |
574
+
575
+ **Returns:** `{scripts: [{name, content, ...}]}`
576
+
577
+ ### sandbox_info
578
+
579
+ | Parameter | Type | Default | Description |
580
+ |-----------|------|---------|-------------|
581
+ | `command` | `str \| None` | `None` | Command name (omit for all) |
582
+
583
+ **Returns:** JSON with sandbox spec, grades, and resource metrics.
584
+
585
+ ---
586
+
587
+ ## MCP Resources
588
+
589
+ | URI | Type | Description |
590
+ |-----|------|-------------|
591
+ | `blq://status` | JSON | Current per-source status |
592
+ | `blq://runs` | JSON | Run history (up to 100) |
593
+ | `blq://events` | JSON | Recent error events |
594
+ | `blq://event/{ref}` | JSON | Single event details |
595
+ | `blq://errors` | JSON | Recent errors (up to 50) |
596
+ | `blq://errors/{run_serial}` | JSON | Errors for a specific run |
597
+ | `blq://warnings` | JSON | Recent warnings (up to 50) |
598
+ | `blq://warnings/{run_serial}` | JSON | Warnings for a specific run |
599
+ | `blq://context/{ref}` | JSON | Log context around an event |
600
+ | `blq://commands` | JSON | Registered commands |
601
+ | `blq://guide` | Markdown | Agent usage guide |
@@ -140,7 +140,7 @@ Usually auto-detection works well. Specify format when:
140
140
  All captured logs are stored in the BIRD database (DuckDB tables with content-addressed blob storage):
141
141
 
142
142
  ```
143
- .lq/
143
+ .bird/
144
144
  ├── blq.duckdb # DuckDB database (events, runs, metadata)
145
145
  ├── blobs/ # Content-addressed blob storage
146
146
  │ └── content/