specsmith 0.3.5__tar.gz → 0.3.6.dev164__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 (164) hide show
  1. {specsmith-0.3.5/src/specsmith.egg-info → specsmith-0.3.6.dev164}/PKG-INFO +12 -7
  2. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/README.md +9 -4
  3. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/pyproject.toml +14 -2
  4. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/agent/providers/ollama.py +21 -7
  5. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/agent/runner.py +104 -5
  6. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/cli.py +178 -0
  7. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/config.py +21 -0
  8. specsmith-0.3.6.dev164/src/specsmith/profiles.py +425 -0
  9. specsmith-0.3.6.dev164/src/specsmith/tool_installer.py +471 -0
  10. specsmith-0.3.6.dev164/src/specsmith/toolrules.py +404 -0
  11. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/vcs_commands.py +3 -2
  12. {specsmith-0.3.5 → specsmith-0.3.6.dev164/src/specsmith.egg-info}/PKG-INFO +12 -7
  13. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith.egg-info/SOURCES.txt +3 -0
  14. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/LICENSE +0 -0
  15. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/setup.cfg +0 -0
  16. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/epistemic/__init__.py +0 -0
  17. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/epistemic/belief.py +0 -0
  18. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/epistemic/certainty.py +0 -0
  19. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/epistemic/failure_graph.py +0 -0
  20. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/epistemic/py.typed +0 -0
  21. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/epistemic/recovery.py +0 -0
  22. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/epistemic/session.py +0 -0
  23. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/epistemic/stress_tester.py +0 -0
  24. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/epistemic/trace.py +0 -0
  25. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/__init__.py +0 -0
  26. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/__main__.py +0 -0
  27. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/agent/__init__.py +0 -0
  28. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/agent/core.py +0 -0
  29. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/agent/hooks.py +0 -0
  30. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/agent/optimizer.py +0 -0
  31. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/agent/profiles/epistemic-auditor.md +0 -0
  32. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/agent/profiles/planner.md +0 -0
  33. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/agent/profiles/verifier.md +0 -0
  34. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/agent/providers/__init__.py +0 -0
  35. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/agent/providers/anthropic.py +0 -0
  36. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/agent/providers/gemini.py +0 -0
  37. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/agent/providers/mistral.py +0 -0
  38. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/agent/providers/openai.py +0 -0
  39. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/agent/skills.py +0 -0
  40. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/agent/tools.py +0 -0
  41. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/architect.py +0 -0
  42. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/auditor.py +0 -0
  43. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/auth.py +0 -0
  44. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/commands/__init__.py +0 -0
  45. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/compressor.py +0 -0
  46. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/credit_analyzer.py +0 -0
  47. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/credits.py +0 -0
  48. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/differ.py +0 -0
  49. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/doctor.py +0 -0
  50. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/epistemic/__init__.py +0 -0
  51. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/epistemic/belief.py +0 -0
  52. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/epistemic/certainty.py +0 -0
  53. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/epistemic/failure_graph.py +0 -0
  54. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/epistemic/recovery.py +0 -0
  55. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/epistemic/stress_tester.py +0 -0
  56. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/executor.py +0 -0
  57. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/exporter.py +0 -0
  58. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/gui/__init__.py +0 -0
  59. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/gui/app.py +0 -0
  60. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/gui/main_window.py +0 -0
  61. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/gui/session_tab.py +0 -0
  62. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/gui/theme.py +0 -0
  63. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/gui/widgets/__init__.py +0 -0
  64. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/gui/widgets/chat_view.py +0 -0
  65. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/gui/widgets/input_bar.py +0 -0
  66. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/gui/widgets/provider_bar.py +0 -0
  67. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/gui/widgets/token_meter.py +0 -0
  68. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/gui/widgets/tool_panel.py +0 -0
  69. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/gui/widgets/update_checker.py +0 -0
  70. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/gui/worker.py +0 -0
  71. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/importer.py +0 -0
  72. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/integrations/__init__.py +0 -0
  73. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/integrations/aider.py +0 -0
  74. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/integrations/base.py +0 -0
  75. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/integrations/claude_code.py +0 -0
  76. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/integrations/copilot.py +0 -0
  77. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/integrations/cursor.py +0 -0
  78. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/integrations/gemini.py +0 -0
  79. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/integrations/warp.py +0 -0
  80. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/integrations/windsurf.py +0 -0
  81. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/languages.py +0 -0
  82. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/ledger.py +0 -0
  83. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/ollama_cmds.py +0 -0
  84. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/patent.py +0 -0
  85. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/phase.py +0 -0
  86. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/plugins.py +0 -0
  87. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/rate_limits.py +0 -0
  88. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/releaser.py +0 -0
  89. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/requirements.py +0 -0
  90. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/scaffolder.py +0 -0
  91. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/session.py +0 -0
  92. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/templates/agents.md.j2 +0 -0
  93. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/templates/community/bug_report.md.j2 +0 -0
  94. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/templates/community/code_of_conduct.md.j2 +0 -0
  95. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/templates/community/contributing.md.j2 +0 -0
  96. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/templates/community/feature_request.md.j2 +0 -0
  97. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/templates/community/license-Apache-2.0.j2 +0 -0
  98. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/templates/community/license-MIT.j2 +0 -0
  99. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/templates/community/pull_request_template.md.j2 +0 -0
  100. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/templates/community/security.md.j2 +0 -0
  101. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/templates/docs/architecture.md.j2 +0 -0
  102. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/templates/docs/mkdocs.yml.j2 +0 -0
  103. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/templates/docs/readthedocs.yaml.j2 +0 -0
  104. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/templates/docs/requirements.md.j2 +0 -0
  105. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/templates/docs/test-spec.md.j2 +0 -0
  106. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/templates/docs/workflow.md.j2 +0 -0
  107. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/templates/editorconfig.j2 +0 -0
  108. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/templates/gitattributes.j2 +0 -0
  109. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/templates/gitignore.j2 +0 -0
  110. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/templates/go/go.mod.j2 +0 -0
  111. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/templates/go/main.go.j2 +0 -0
  112. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/templates/governance/belief-registry.md.j2 +0 -0
  113. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/templates/governance/context-budget.md.j2 +0 -0
  114. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/templates/governance/drift-metrics.md.j2 +0 -0
  115. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/templates/governance/epistemic-axioms.md.j2 +0 -0
  116. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/templates/governance/failure-modes.md.j2 +0 -0
  117. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/templates/governance/roles.md.j2 +0 -0
  118. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/templates/governance/rules.md.j2 +0 -0
  119. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/templates/governance/uncertainty-map.md.j2 +0 -0
  120. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/templates/governance/verification.md.j2 +0 -0
  121. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/templates/governance/workflow.md.j2 +0 -0
  122. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/templates/js/package.json.j2 +0 -0
  123. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/templates/ledger.md.j2 +0 -0
  124. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/templates/python/cli.py.j2 +0 -0
  125. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/templates/python/init.py.j2 +0 -0
  126. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/templates/python/pyproject.toml.j2 +0 -0
  127. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/templates/readme.md.j2 +0 -0
  128. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/templates/rust/Cargo.toml.j2 +0 -0
  129. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/templates/rust/main.rs.j2 +0 -0
  130. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/templates/scripts/exec.cmd.j2 +0 -0
  131. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/templates/scripts/exec.sh.j2 +0 -0
  132. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/templates/scripts/run.cmd.j2 +0 -0
  133. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/templates/scripts/run.sh.j2 +0 -0
  134. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/templates/scripts/setup.cmd.j2 +0 -0
  135. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/templates/scripts/setup.sh.j2 +0 -0
  136. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/templates/workflows/release.yml.j2 +0 -0
  137. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/tools.py +0 -0
  138. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/trace.py +0 -0
  139. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/updater.py +0 -0
  140. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/upgrader.py +0 -0
  141. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/validator.py +0 -0
  142. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/vcs/__init__.py +0 -0
  143. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/vcs/base.py +0 -0
  144. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/vcs/bitbucket.py +0 -0
  145. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/vcs/github.py +0 -0
  146. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/vcs/gitlab.py +0 -0
  147. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith/workspace.py +0 -0
  148. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith.egg-info/dependency_links.txt +0 -0
  149. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith.egg-info/entry_points.txt +0 -0
  150. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith.egg-info/requires.txt +0 -0
  151. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/src/specsmith.egg-info/top_level.txt +0 -0
  152. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/tests/test_auditor.py +0 -0
  153. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/tests/test_cli.py +0 -0
  154. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/tests/test_compressor.py +0 -0
  155. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/tests/test_epistemic.py +0 -0
  156. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/tests/test_importer.py +0 -0
  157. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/tests/test_integrations.py +0 -0
  158. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/tests/test_optimizer.py +0 -0
  159. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/tests/test_rate_limits.py +0 -0
  160. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/tests/test_scaffolder.py +0 -0
  161. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/tests/test_smoke.py +0 -0
  162. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/tests/test_tools.py +0 -0
  163. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/tests/test_validator.py +0 -0
  164. {specsmith-0.3.5 → specsmith-0.3.6.dev164}/tests/test_vcs.py +0 -0
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: specsmith
3
- Version: 0.3.5
4
- Summary: Applied Epistemic Engineering toolkit — forge epistemically-governed scaffolds, stress-test belief systems, and run AEE pipelines.
3
+ Version: 0.3.6.dev164
4
+ Summary: Applied Epistemic Engineering toolkit — AEE agent sessions, execution profiles, FPGA/HDL governance, tool installer, 50+ CLI commands.
5
5
  Author: BitConcepts
6
6
  License-Expression: MIT
7
7
  Project-URL: Homepage, https://github.com/BitConcepts/specsmith
@@ -9,7 +9,7 @@ Project-URL: Documentation, https://specsmith.readthedocs.io
9
9
  Project-URL: Repository, https://github.com/BitConcepts/specsmith
10
10
  Project-URL: Changelog, https://github.com/BitConcepts/specsmith/blob/main/CHANGELOG.md
11
11
  Project-URL: Issues, https://github.com/BitConcepts/specsmith/issues
12
- Keywords: agentic,scaffold,governance,agents-md,cli,epistemic-engineering,belief-artifacts,stress-testing,certainty,trace-vault,aee,knowledge-engineering
12
+ Keywords: agentic,scaffold,governance,agents-md,cli,epistemic-engineering,belief-artifacts,stress-testing,certainty,trace-vault,aee,knowledge-engineering,fpga,hdl,vhdl,execution-profiles,tool-installer,llm,ollama,requirements-management
13
13
  Classifier: Development Status :: 4 - Beta
14
14
  Classifier: Environment :: Console
15
15
  Classifier: Intended Audience :: Developers
@@ -194,15 +194,18 @@ The **specsmith AEE Workbench** VS Code extension is the flagship client:
194
194
  ```
195
195
 
196
196
  **Key features:**
197
- - **5-tab Governance Panel** — Project / Tools / Files / Updates & System / Actions & AI
197
+ - **6-tab Settings panel** — Project / Tools / Files / Updates / Actions / Execution
198
+ - **Execution profiles** — safe (read-only) / standard / open / admin; custom allow/block command lists stored in `scaffold.yml`
198
199
  - **AEE phase indicator** — shows current phase with readiness %, Next Phase button, and phase selector
199
200
  - **AI agent sessions** — independent process per project, JSONL bridge, chat with file injection
200
201
  - **Live model listing** — Anthropic, OpenAI, Gemini, Mistral, local Ollama (GPU-aware)
201
202
  - **Ollama integration** — browse curated catalog, download models with progress, task-based suggestions
202
203
  - **FPGA/HDL tool support** — vivado, gtkwave, vsg, ghdl, verilator, yosys, nextpnr, and 15 more
204
+ - **Tool installer** — scan installed tools; one-click install via winget/brew/apt for missing tools
205
+ - **Tool rules** — curated AI context rules for 20+ tools (VSG, GHDL, Verilator, ruff, mypy, etc.) auto-injected into agent system prompt
203
206
  - **API key management** — stored in OS credential store (Windows Credential Manager / macOS Keychain)
204
- - **Update checker** — PyPI version check with Install Update button, system info panel
205
- - **Auto-open** — governance panel opens automatically when VS Code starts with a workspace
207
+ - **Update checker** — PyPI version check, Install Update button, release channel selector (stable / pre-release)
208
+ - **Auto-open** — Settings panel always opens alongside every new session; never a blank pane
206
209
 
207
210
  **[→ specsmith-vscode on GitHub](https://github.com/BitConcepts/specsmith-vscode)**
208
211
 
@@ -232,7 +235,7 @@ specsmith supports FPGA-specific project types with full governance:
232
235
 
233
236
  ```yaml
234
237
  # scaffold.yml
235
- type: fpga-rtl-xilinx
238
+ type: fpga-rtl-amd # or fpga-rtl-intel / fpga-rtl-lattice / fpga-rtl
236
239
  fpga_tools:
237
240
  - vivado
238
241
  - gtkwave
@@ -264,6 +267,8 @@ Supported tools: **Synthesis:** vivado, quartus, radiant, diamond, gowin.
264
267
 
265
268
  **VCS:** `commit` `push` `sync` `branch` `pr` `status`
266
269
 
270
+ **Tools:** `tools scan [--fpga]` `tools install <tool>` `tools rules [--tool] [--list]`
271
+
267
272
  **Tools:** `exec` `ps` `abort` `watch` `optimize` `credits` `self-update`
268
273
 
269
274
  **Auth:** `auth set/list/remove/check`
@@ -129,15 +129,18 @@ The **specsmith AEE Workbench** VS Code extension is the flagship client:
129
129
  ```
130
130
 
131
131
  **Key features:**
132
- - **5-tab Governance Panel** — Project / Tools / Files / Updates & System / Actions & AI
132
+ - **6-tab Settings panel** — Project / Tools / Files / Updates / Actions / Execution
133
+ - **Execution profiles** — safe (read-only) / standard / open / admin; custom allow/block command lists stored in `scaffold.yml`
133
134
  - **AEE phase indicator** — shows current phase with readiness %, Next Phase button, and phase selector
134
135
  - **AI agent sessions** — independent process per project, JSONL bridge, chat with file injection
135
136
  - **Live model listing** — Anthropic, OpenAI, Gemini, Mistral, local Ollama (GPU-aware)
136
137
  - **Ollama integration** — browse curated catalog, download models with progress, task-based suggestions
137
138
  - **FPGA/HDL tool support** — vivado, gtkwave, vsg, ghdl, verilator, yosys, nextpnr, and 15 more
139
+ - **Tool installer** — scan installed tools; one-click install via winget/brew/apt for missing tools
140
+ - **Tool rules** — curated AI context rules for 20+ tools (VSG, GHDL, Verilator, ruff, mypy, etc.) auto-injected into agent system prompt
138
141
  - **API key management** — stored in OS credential store (Windows Credential Manager / macOS Keychain)
139
- - **Update checker** — PyPI version check with Install Update button, system info panel
140
- - **Auto-open** — governance panel opens automatically when VS Code starts with a workspace
142
+ - **Update checker** — PyPI version check, Install Update button, release channel selector (stable / pre-release)
143
+ - **Auto-open** — Settings panel always opens alongside every new session; never a blank pane
141
144
 
142
145
  **[→ specsmith-vscode on GitHub](https://github.com/BitConcepts/specsmith-vscode)**
143
146
 
@@ -167,7 +170,7 @@ specsmith supports FPGA-specific project types with full governance:
167
170
 
168
171
  ```yaml
169
172
  # scaffold.yml
170
- type: fpga-rtl-xilinx
173
+ type: fpga-rtl-amd # or fpga-rtl-intel / fpga-rtl-lattice / fpga-rtl
171
174
  fpga_tools:
172
175
  - vivado
173
176
  - gtkwave
@@ -199,6 +202,8 @@ Supported tools: **Synthesis:** vivado, quartus, radiant, diamond, gowin.
199
202
 
200
203
  **VCS:** `commit` `push` `sync` `branch` `pr` `status`
201
204
 
205
+ **Tools:** `tools scan [--fpga]` `tools install <tool>` `tools rules [--tool] [--list]`
206
+
202
207
  **Tools:** `exec` `ps` `abort` `watch` `optimize` `credits` `self-update`
203
208
 
204
209
  **Auth:** `auth set/list/remove/check`
@@ -4,8 +4,8 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "specsmith"
7
- version = "0.3.5"
8
- description = "Applied Epistemic Engineering toolkit — forge epistemically-governed scaffolds, stress-test belief systems, and run AEE pipelines."
7
+ version = "0.3.6.dev164"
8
+ description = "Applied Epistemic Engineering toolkit — AEE agent sessions, execution profiles, FPGA/HDL governance, tool installer, 50+ CLI commands."
9
9
  readme = "README.md"
10
10
  license = "MIT"
11
11
  requires-python = ">=3.10"
@@ -16,6 +16,8 @@ keywords = [
16
16
  "agentic", "scaffold", "governance", "agents-md", "cli",
17
17
  "epistemic-engineering", "belief-artifacts", "stress-testing",
18
18
  "certainty", "trace-vault", "aee", "knowledge-engineering",
19
+ "fpga", "hdl", "vhdl", "execution-profiles", "tool-installer",
20
+ "llm", "ollama", "requirements-management",
19
21
  ]
20
22
  classifiers = [
21
23
  "Development Status :: 4 - Beta",
@@ -99,6 +101,11 @@ line-length = 100
99
101
  [tool.ruff.lint]
100
102
  select = ["E", "F", "W", "I", "UP", "B", "SIM"]
101
103
 
104
+ [tool.ruff.lint.per-file-ignores]
105
+ # Long rule text and install command strings in documentation modules
106
+ "src/specsmith/toolrules.py" = ["E501"]
107
+ "src/specsmith/tool_installer.py" = ["E501"]
108
+
102
109
  [tool.mypy]
103
110
  python_version = "3.10"
104
111
  strict = true
@@ -120,6 +127,8 @@ module = [
120
127
  "google.*",
121
128
  "yaml",
122
129
  "yaml.*",
130
+ "keyring", # optional OS credential store; stubs not published
131
+ "keyring.*",
123
132
  ]
124
133
  ignore_missing_imports = true
125
134
 
@@ -140,6 +149,9 @@ module = [
140
149
  "specsmith.importer",
141
150
  "specsmith.agent.providers.gemini",
142
151
  "specsmith.agent.runner",
152
+ "specsmith.profiles",
153
+ "specsmith.toolrules",
154
+ "specsmith.tool_installer",
143
155
  ]
144
156
  ignore_errors = true
145
157
 
@@ -96,18 +96,32 @@ class OllamaProvider:
96
96
  ) -> CompletionResponse:
97
97
  """Complete using the native /api/chat endpoint.
98
98
 
99
- Tool calling is attempted first; if the model returns an error
100
- indicating no tool support (HTTP 400 etc.) we retry without tools.
99
+ Tool calling is attempted first; if the model returns HTTP 400
100
+ (tool calling not supported) we retry without tools. If the native
101
+ fallback *also* returns 400 (common when the ``think`` parameter is
102
+ unsupported by an older Ollama server) we strip ``think`` and retry.
101
103
  """
102
104
  if tools:
103
105
  try:
104
106
  return self._complete_with_tools(messages, tools, max_tokens)
105
107
  except Exception as exc: # noqa: BLE001
106
- if _is_tool_fallback_error(exc):
107
- # Model doesn't support tool calling — degrade gracefully
108
- return self._complete_native(messages, max_tokens)
109
- raise
110
- return self._complete_native(messages, max_tokens)
108
+ if not _is_tool_fallback_error(exc):
109
+ raise
110
+ # Fall through to native (no-tools) completion below
111
+ return self._complete_native_with_fallback(messages, max_tokens)
112
+
113
+ def _complete_native_with_fallback(
114
+ self, messages: list[Message], max_tokens: int
115
+ ) -> CompletionResponse:
116
+ """Call _complete_native; if it fails with 400 and think is set, retry without it."""
117
+ try:
118
+ return self._complete_native(messages, max_tokens)
119
+ except Exception as exc: # noqa: BLE001
120
+ if self._think is not None and _is_tool_fallback_error(exc):
121
+ # Older Ollama doesn't support 'think' — disable permanently for this session
122
+ self._think = None
123
+ return self._complete_native(messages, max_tokens)
124
+ raise
111
125
 
112
126
  def _complete_native(self, messages: list[Message], max_tokens: int) -> CompletionResponse:
113
127
  """Plain chat completion without tools."""
@@ -112,8 +112,10 @@ def build_system_prompt(
112
112
  lines = content.splitlines()[:200]
113
113
  agents_md = "\n".join(lines)
114
114
 
115
- # Load spec version from scaffold.yml
115
+ # Load scaffold.yml for spec_version, project type, and FPGA tools
116
116
  spec_version = "unknown"
117
+ project_type = ""
118
+ fpga_tools: list[str] = []
117
119
  scaffold_path = root / "scaffold.yml"
118
120
  if scaffold_path.exists():
119
121
  try:
@@ -122,6 +124,8 @@ def build_system_prompt(
122
124
  with open(scaffold_path) as f:
123
125
  raw = yaml.safe_load(f) or {}
124
126
  spec_version = raw.get("spec_version", "unknown")
127
+ project_type = str(raw.get("type", ""))
128
+ fpga_tools = list(raw.get("fpga_tools", []) or [])
125
129
  except Exception: # noqa: BLE001
126
130
  pass
127
131
 
@@ -148,9 +152,26 @@ H13: All proposals must state their epistemic boundaries. Hidden assumptions are
148
152
  agents_md or f"Spec version: {spec_version}. AGENTS.md not found — run specsmith audit."
149
153
  )
150
154
 
155
+ # Load tool-specific rules for this project type
156
+ tool_rules_section = ""
157
+ if project_type:
158
+ try:
159
+ from specsmith.toolrules import get_rules_for_project
160
+
161
+ rules_text = get_rules_for_project(project_type, fpga_tools, max_chars=4000)
162
+ if rules_text:
163
+ tool_rules_section = f"\n## Tool Rules\n{rules_text}\n"
164
+ except Exception: # noqa: BLE001
165
+ pass
166
+
151
167
  prompt = f"""You are an AEE-integrated specsmith agent for this project.
152
- ALWAYS respond in English only, regardless of the user's language or your default language.
153
- Do not use Chinese, Japanese, Korean, or any other non-English language at any time.
168
+
169
+ LANGUAGE RULE (HARD CONSTRAINT NEVER VIOLATE):
170
+ Respond ONLY in English. Every single response must be in English.
171
+ Never use Chinese (中文), Japanese (日本語), Korean (한국어), French, German, Spanish,
172
+ Arabic, or ANY other non-English language — not even a single word.
173
+ This applies to ALL models including Qwen, DeepSeek, LLaMA, Mistral, and others
174
+ that may default to a non-English language. ENGLISH ONLY, ALWAYS.
154
175
 
155
176
  ## Project Governance
156
177
  {governance_text}
@@ -164,7 +185,7 @@ Do not use Chinese, Japanese, Korean, or any other non-English language at any t
164
185
  - The ledger + accepted repo state is authority
165
186
  {aee_section}
166
187
  {skills_section}
167
-
188
+ {tool_rules_section}
168
189
  ## Quick Commands
169
190
  Users may type these shortcuts:
170
191
  - `start` — new session protocol (sync + update check + load state)
@@ -213,7 +234,10 @@ class AgentRunner:
213
234
  }
214
235
 
215
236
  QUICK_COMMANDS = {
216
- "start": "Run session start protocol: sync, load AGENTS.md, read last LEDGER.md entries",
237
+ "start": (
238
+ "[RESPOND IN ENGLISH ONLY] "
239
+ "Run session start protocol: sync, load AGENTS.md, read last LEDGER.md entries"
240
+ ),
217
241
  "resume": "Resume from last LEDGER.md entry — summarize state and propose next task",
218
242
  "save": "Write a ledger entry summarizing this session's work",
219
243
  "audit": "Run specsmith audit --fix",
@@ -252,6 +276,11 @@ class AgentRunner:
252
276
  self._hooks = HookRegistry()
253
277
  self._system_prompt = ""
254
278
 
279
+ # Execution profile — loaded from scaffold.yml at session start
280
+ from specsmith import profiles
281
+
282
+ self._profile = profiles.load_from_scaffold(self.project_dir)
283
+
255
284
  # Token / credit optimization engine (opt-in)
256
285
  self._optimizer: OptimizationEngine | None = (
257
286
  OptimizationEngine(
@@ -474,6 +503,8 @@ class AgentRunner:
474
503
  self, tool_calls: list[dict[str, Any]], silent: bool = False
475
504
  ) -> list[ToolResult]:
476
505
  """Execute tool calls and return results."""
506
+ from specsmith import profiles as _profiles
507
+
477
508
  results: list[ToolResult] = []
478
509
  for tc in tool_calls:
479
510
  name = tc.get("name", "")
@@ -486,6 +517,74 @@ class AgentRunner:
486
517
  else:
487
518
  self._print(f"\n[Tool: {name}]")
488
519
 
520
+ # ── Execution profile enforcement ──────────────────────────────────
521
+ tool_ok, tool_reason = _profiles.check_tool_allowed(self._profile, name)
522
+ if not tool_ok:
523
+ blocked_msg = f"[BLOCKED by profile '{self._profile.name}'] {tool_reason}"
524
+ if not silent:
525
+ if self._json_events:
526
+ self._emit_event(type="tool_blocked", name=name, reason=tool_reason)
527
+ else:
528
+ self._print(f" ✗ {blocked_msg}")
529
+ results.append(
530
+ ToolResult(
531
+ tool_name=name,
532
+ tool_call_id=call_id,
533
+ content=blocked_msg,
534
+ error=True,
535
+ )
536
+ )
537
+ continue
538
+
539
+ # For run_command: check the command string
540
+ if name == "run_command" and "command" in inputs:
541
+ cmd_ok, cmd_reason = _profiles.check_command_allowed(
542
+ self._profile, str(inputs["command"])
543
+ )
544
+ if not cmd_ok:
545
+ blocked_msg = f"[BLOCKED by profile '{self._profile.name}'] {cmd_reason}"
546
+ if not silent:
547
+ if self._json_events:
548
+ self._emit_event(
549
+ type="tool_blocked",
550
+ name=name,
551
+ command=inputs["command"],
552
+ reason=cmd_reason,
553
+ )
554
+ else:
555
+ self._print(f" ✗ {blocked_msg}")
556
+ results.append(
557
+ ToolResult(
558
+ tool_name=name,
559
+ tool_call_id=call_id,
560
+ content=blocked_msg,
561
+ error=True,
562
+ )
563
+ )
564
+ continue
565
+
566
+ # For write_file: check file-write permission and size
567
+ if name == "write_file" and "content" in inputs:
568
+ write_ok, write_reason = _profiles.check_write_allowed(
569
+ self._profile, str(inputs["content"])
570
+ )
571
+ if not write_ok:
572
+ blocked_msg = f"[BLOCKED by profile '{self._profile.name}'] {write_reason}"
573
+ if not silent:
574
+ if self._json_events:
575
+ self._emit_event(type="tool_blocked", name=name, reason=write_reason)
576
+ else:
577
+ self._print(f" ✗ {blocked_msg}")
578
+ results.append(
579
+ ToolResult(
580
+ tool_name=name,
581
+ tool_call_id=call_id,
582
+ content=blocked_msg,
583
+ error=True,
584
+ )
585
+ )
586
+ continue
587
+
489
588
  # Fire pre_tool hooks
490
589
  pre_ctx = HookContext(
491
590
  trigger=HookTrigger.PRE_TOOL,
@@ -4059,6 +4059,184 @@ def tools_scan_cmd(project_dir: str, as_json: bool, fpga: bool) -> None:
4059
4059
  )
4060
4060
 
4061
4061
 
4062
+ @tools_group.command(name="install")
4063
+ @click.argument("tool", required=False, default="")
4064
+ @click.option(
4065
+ "--list",
4066
+ "list_all",
4067
+ is_flag=True,
4068
+ default=False,
4069
+ help="List all known installable tools.",
4070
+ )
4071
+ @click.option(
4072
+ "--category",
4073
+ default="",
4074
+ help="Filter by category (fpga, python, c, rust, go, devops, linux, doc, js, other).",
4075
+ )
4076
+ @click.option(
4077
+ "--dry-run",
4078
+ is_flag=True,
4079
+ default=False,
4080
+ help="Print the install command without running it.",
4081
+ )
4082
+ @click.option(
4083
+ "--yes",
4084
+ "-y",
4085
+ is_flag=True,
4086
+ default=False,
4087
+ help="Run the install command without prompting.",
4088
+ )
4089
+ def tools_install_cmd(tool: str, list_all: bool, category: str, dry_run: bool, yes: bool) -> None:
4090
+ """Show or run the install command for a development tool.
4091
+
4092
+ TOOL is the tool key (e.g. ghdl, ruff, verilator). Run with --list to see
4093
+ all available tools. The best install method for the current platform is
4094
+ selected automatically (winget on Windows, brew on macOS, apt/dnf on Linux).
4095
+ """
4096
+ import subprocess
4097
+
4098
+ from specsmith.tool_installer import (
4099
+ KNOWN_TOOLS,
4100
+ ToolInstallInfo,
4101
+ get_install_command,
4102
+ list_tools,
4103
+ )
4104
+
4105
+ if list_all or not tool:
4106
+ items: list[ToolInstallInfo] = list_tools(category=category or None)
4107
+ console.print(f"[bold]Known installable tools[/bold] ({len(items)})\n")
4108
+ cats: dict[str, list[ToolInstallInfo]] = {}
4109
+ for t in items:
4110
+ cats.setdefault(t.category, []).append(t)
4111
+ for cat, ts in sorted(cats.items()):
4112
+ console.print(f" [teal]{cat}[/teal]")
4113
+ for t in ts:
4114
+ console.print(f" [dim]{t.key:<25s}[/dim] {t.display_name}")
4115
+ console.print()
4116
+ console.print(
4117
+ " Run [bold]specsmith tools install <key>[/bold] to get the install command."
4118
+ )
4119
+ return
4120
+
4121
+ info = KNOWN_TOOLS.get(tool)
4122
+ if info is None:
4123
+ # Fuzzy fallback: substring match
4124
+ matches = [k for k in KNOWN_TOOLS if tool.lower() in k.lower()]
4125
+ if matches:
4126
+ console.print(
4127
+ f"[yellow]Unknown tool '{tool}'. Did you mean: {', '.join(matches[:5])}?[/yellow]"
4128
+ )
4129
+ else:
4130
+ console.print(
4131
+ f"[red]Unknown tool '{tool}'.[/red] "
4132
+ "Run [bold]specsmith tools install --list[/bold] "
4133
+ "to see available tools."
4134
+ )
4135
+ raise SystemExit(1)
4136
+
4137
+ cmd = get_install_command(tool)
4138
+ if cmd is None:
4139
+ if info.manual:
4140
+ console.print(
4141
+ f"[yellow]No automatic install for '{info.display_name}' on this platform.[/yellow]"
4142
+ )
4143
+ console.print(f" Manual install: {info.manual}")
4144
+ else:
4145
+ console.print(f"[red]No install method known for '{tool}'.[/red]")
4146
+ return
4147
+
4148
+ if info.notes:
4149
+ console.print(f"[dim]Note:[/dim] {info.notes}")
4150
+
4151
+ if dry_run or not yes:
4152
+ console.print(f"\n[bold]Install command for {info.display_name}:[/bold]")
4153
+ console.print(f" [teal]{cmd}[/teal]")
4154
+ if not dry_run and not yes:
4155
+ confirmed = console.input("\nRun this command now? [[bold]y[/bold]/N] ").strip().lower()
4156
+ if confirmed not in ("y", "yes"):
4157
+ console.print("[dim]Aborted.[/dim]")
4158
+ return
4159
+ if not dry_run:
4160
+ console.print(f"[bold]Running:[/bold] {cmd}")
4161
+ result = subprocess.run(cmd, shell=True, check=False) # noqa: S602
4162
+ if result.returncode != 0:
4163
+ console.print(f"[red]Install failed (exit {result.returncode}).[/red]")
4164
+ raise SystemExit(result.returncode)
4165
+ console.print("[green]\u2713[/green] Done.")
4166
+
4167
+
4168
+ @tools_group.command(name="rules")
4169
+ @click.option("--project-dir", type=click.Path(exists=True), default=".")
4170
+ @click.option(
4171
+ "--tool",
4172
+ "tool_key",
4173
+ default="",
4174
+ help="Show rules for a specific tool key (e.g. ghdl, ruff).",
4175
+ )
4176
+ @click.option(
4177
+ "--list",
4178
+ "list_all",
4179
+ is_flag=True,
4180
+ default=False,
4181
+ help="List all tools that have AI context rules.",
4182
+ )
4183
+ def tools_rules_cmd(project_dir: str, tool_key: str, list_all: bool) -> None:
4184
+ """Show the AI context rules injected into the agent system prompt.
4185
+
4186
+ Without options, shows rules for the current project type (from scaffold.yml).
4187
+ Use --tool to show rules for a specific tool, or --list to see all available.
4188
+ """
4189
+ from specsmith.toolrules import TOOL_RULES, get_rules_for_project
4190
+
4191
+ if list_all:
4192
+ console.print(f"[bold]Tool rules available[/bold] ({len(TOOL_RULES)} tools):\n")
4193
+ for key in sorted(TOOL_RULES):
4194
+ first_line = TOOL_RULES[key].strip().splitlines()[0].lstrip("# ").strip()
4195
+ console.print(f" [teal]{key:<25s}[/teal] {first_line}")
4196
+ console.print("\n Use [bold]specsmith tools rules --tool <key>[/bold] to view full rules.")
4197
+ return
4198
+
4199
+ if tool_key:
4200
+ if tool_key not in TOOL_RULES:
4201
+ matches = [k for k in TOOL_RULES if tool_key.lower() in k.lower()]
4202
+ if matches:
4203
+ console.print(
4204
+ f"[yellow]No rules for '{tool_key}'. Similar: {', '.join(matches[:5])}[/yellow]"
4205
+ )
4206
+ else:
4207
+ console.print(f"[red]No rules for '{tool_key}'.[/red]")
4208
+ raise SystemExit(1)
4209
+ console.print(TOOL_RULES[tool_key])
4210
+ return
4211
+
4212
+ # Project-level rules from scaffold.yml
4213
+ import yaml
4214
+
4215
+ root = Path(project_dir).resolve()
4216
+ scaffold_path = root / "scaffold.yml"
4217
+ if not scaffold_path.exists():
4218
+ console.print(
4219
+ "[yellow]No scaffold.yml found. "
4220
+ "Run specsmith init or use --tool to view a specific tool.[/yellow]"
4221
+ )
4222
+ raise SystemExit(1)
4223
+
4224
+ with open(scaffold_path) as f:
4225
+ raw = yaml.safe_load(f) or {}
4226
+ project_type = str(raw.get("type", "cli-python"))
4227
+ fpga_tools: list[str] = raw.get("fpga_tools", []) or []
4228
+
4229
+ rules = get_rules_for_project(project_type, fpga_tools, max_chars=20000)
4230
+ if not rules:
4231
+ console.print(
4232
+ f"[yellow]No tool rules configured for project type '{project_type}'.[/yellow]"
4233
+ )
4234
+ return
4235
+
4236
+ console.print(f"[bold]Tool rules for project type:[/bold] [teal]{project_type}[/teal]\n")
4237
+ console.print(rules)
4238
+
4239
+
4062
4240
  main.add_command(tools_group)
4063
4241
 
4064
4242
 
@@ -195,6 +195,27 @@ class ProjectConfig(BaseModel):
195
195
  description="Agent integrations to generate (agents-md, warp, claude-code, cursor, etc.)",
196
196
  )
197
197
 
198
+ # Agent execution profile
199
+ execution_profile: str = Field(
200
+ default="standard",
201
+ description=(
202
+ "Agent execution profile: safe (read-only), standard (default), "
203
+ "open (most commands), admin (no limits)."
204
+ ),
205
+ )
206
+ custom_allowed_commands: list[str] = Field(
207
+ default_factory=list,
208
+ description="Extra allowed command prefixes merged with the active execution profile.",
209
+ )
210
+ custom_blocked_commands: list[str] = Field(
211
+ default_factory=list,
212
+ description="Extra blocked command prefixes merged with the active execution profile.",
213
+ )
214
+ custom_blocked_tools: list[str] = Field(
215
+ default_factory=list,
216
+ description="Agent tool names to always block, regardless of the execution profile.",
217
+ )
218
+
198
219
  # Applied Epistemic Engineering configuration
199
220
  enable_epistemic: bool = Field(
200
221
  default=False,