specsmith 0.10.1.dev293__tar.gz → 0.10.1.dev295__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.
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/PKG-INFO +1 -1
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/pyproject.toml +1 -1
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/governance_logic.py +40 -0
- specsmith-0.10.1.dev295/src/specsmith/mcp_generator.py +210 -0
- specsmith-0.10.1.dev295/src/specsmith/skills_builder.py +193 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith.egg-info/PKG-INFO +1 -1
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith.egg-info/SOURCES.txt +3 -0
- specsmith-0.10.1.dev295/tests/test_skills_mcp.py +109 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/LICENSE +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/README.md +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/setup.cfg +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/epistemic/__init__.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/epistemic/belief.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/epistemic/certainty.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/epistemic/failure_graph.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/epistemic/py.typed +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/epistemic/recovery.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/epistemic/session.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/epistemic/stress_tester.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/epistemic/trace.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/__init__.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/__main__.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/agent/__init__.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/agent/broker.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/agent/chat_runner.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/agent/cleanup.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/agent/core.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/agent/endpoints.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/agent/events.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/agent/execution_profiles.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/agent/fallback.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/agent/hf_sync.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/agent/indexer.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/agent/mcp.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/agent/memory.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/agent/model_intelligence.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/agent/orchestrator.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/agent/permissions.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/agent/profiles.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/agent/provider_registry.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/agent/repl.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/agent/router.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/agent/rules.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/agent/runner.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/agent/safety.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/agent/spawner.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/agent/suggester.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/agent/teams.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/agent/tools.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/agent/verifier.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/agent/voice.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/architect.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/auditor.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/auth.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/block_export.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/cli.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/commands/__init__.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/commands/intelligence.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/compliance.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/compressor.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/config.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/console_utils.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/context_window.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/credit_analyzer.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/credits.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/datasources/__init__.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/datasources/base.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/datasources/citations.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/datasources/fpd.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/datasources/odp.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/datasources/patentsview.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/datasources/pfw.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/datasources/ppubs.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/datasources/ptab.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/differ.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/doctor.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/drive.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/editor.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/epistemic/__init__.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/epistemic/belief.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/epistemic/certainty.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/epistemic/failure_graph.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/epistemic/recovery.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/epistemic/stress_tester.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/esdb/__init__.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/esdb/bridge.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/eval/__init__.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/eval/builtins.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/eval/runner.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/executor.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/exporter.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/gui/__init__.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/gui/app.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/gui/main_window.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/gui/session_tab.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/gui/theme.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/gui/widgets/__init__.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/gui/widgets/chat_view.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/gui/widgets/input_bar.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/gui/widgets/provider_bar.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/gui/widgets/token_meter.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/gui/widgets/tool_panel.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/gui/widgets/update_checker.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/gui/worker.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/history_search.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/importer.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/instinct.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/integrations/__init__.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/integrations/agent_skill.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/integrations/aider.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/integrations/base.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/integrations/claude_code.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/integrations/copilot.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/integrations/cursor.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/integrations/gemini.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/integrations/windsurf.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/languages.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/ledger.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/patent.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/paths.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/phase.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/plugins.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/profiles.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/rate_limits.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/releaser.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/requirements.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/requirements_parser.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/retrieval.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/safe_write.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/scaffolder.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/serve.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/session.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/session_init.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/skills.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/sync.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/agents.md.j2 +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/community/bug_report.md.j2 +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/community/code_of_conduct.md.j2 +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/community/contributing.md.j2 +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/community/feature_request.md.j2 +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/community/license-Apache-2.0.j2 +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/community/license-MIT.j2 +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/community/pull_request_template.md.j2 +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/community/security.md.j2 +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/docs/architecture.md.j2 +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/docs/mkdocs.yml.j2 +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/docs/readthedocs.yaml.j2 +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/docs/requirements.md.j2 +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/docs/test-spec.md.j2 +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/editorconfig.j2 +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/gitattributes.j2 +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/gitignore.j2 +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/go/go.mod.j2 +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/go/main.go.j2 +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/governance/belief-registry.md.j2 +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/governance/context-budget.md.j2 +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/governance/drift-metrics.md.j2 +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/governance/epistemic-axioms.md.j2 +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/governance/failure-modes.md.j2 +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/governance/lifecycle.md.j2 +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/governance/roles.md.j2 +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/governance/rules.md.j2 +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/governance/session-protocol.md.j2 +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/governance/uncertainty-map.md.j2 +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/governance/verification.md.j2 +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/js/package.json.j2 +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/ledger.md.j2 +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/python/cli.py.j2 +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/python/init.py.j2 +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/python/pyproject.toml.j2 +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/readme.md.j2 +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/rust/Cargo.toml.j2 +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/rust/main.rs.j2 +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/scripts/exec.cmd.j2 +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/scripts/exec.sh.j2 +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/scripts/run.cmd.j2 +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/scripts/run.sh.j2 +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/scripts/setup.cmd.j2 +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/scripts/setup.sh.j2 +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/templates/workflows/release.yml.j2 +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/tool_installer.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/toolrules.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/tools.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/trace.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/updater.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/upgrader.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/validator.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/vcs/__init__.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/vcs/base.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/vcs/bitbucket.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/vcs/github.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/vcs/gitlab.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/vcs_commands.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/wireframes.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/workspace.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith.egg-info/dependency_links.txt +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith.egg-info/entry_points.txt +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith.egg-info/requires.txt +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith.egg-info/top_level.txt +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_CMD_001.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_agent_profiles.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_agent_runner_ready.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_auditor.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_chat_diff_decision.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_chat_runner_openai_compat.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_chat_stdin_protocol.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_cli.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_cli_workflows_history_drive.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_compliance.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_compressor.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_e2e_nexus.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_endpoints_cli.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_endpoints_store.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_epistemic.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_fallback_chain.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_importer.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_integrations.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_intelligence.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_mcp_client.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_new_modules.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_nexus.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_permissions.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_phase1_4_new.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_phase34_completion.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_rate_limits.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_scaffolder.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_skill_marketplace.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_smoke.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_suggester.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_tools.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_validator.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_vcs.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_warp_parity.py +0 -0
- {specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/tests/test_warp_parity_followup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: specsmith
|
|
3
|
-
Version: 0.10.1.
|
|
3
|
+
Version: 0.10.1.dev295
|
|
4
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
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "specsmith"
|
|
7
|
-
version = "0.10.1.
|
|
7
|
+
version = "0.10.1.dev295"
|
|
8
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"
|
|
@@ -614,6 +614,46 @@ class GovernanceHTTPServer:
|
|
|
614
614
|
except Exception as exc: # noqa: BLE001
|
|
615
615
|
self._json_err(str(exc), code=500)
|
|
616
616
|
|
|
617
|
+
# ── Skills ───────────────────────────────────────────
|
|
618
|
+
elif self.path == "/api/skills":
|
|
619
|
+
try:
|
|
620
|
+
from specsmith.skills_builder import list_skills
|
|
621
|
+
|
|
622
|
+
skills = list_skills(project_dir)
|
|
623
|
+
self._json_ok({"skills": [s.to_dict() for s in skills]})
|
|
624
|
+
except Exception as exc: # noqa: BLE001
|
|
625
|
+
self._json_err(str(exc), code=500)
|
|
626
|
+
|
|
627
|
+
# ── Eval ────────────────────────────────────────────
|
|
628
|
+
elif self.path == "/api/eval/suites":
|
|
629
|
+
try:
|
|
630
|
+
from specsmith.eval.builtins import list_suites
|
|
631
|
+
|
|
632
|
+
suites = list_suites()
|
|
633
|
+
self._json_ok({"suites": [s.to_dict() for s in suites]})
|
|
634
|
+
except Exception as exc: # noqa: BLE001
|
|
635
|
+
self._json_err(str(exc), code=500)
|
|
636
|
+
|
|
637
|
+
# ── Teams ───────────────────────────────────────────
|
|
638
|
+
elif self.path == "/api/teams":
|
|
639
|
+
try:
|
|
640
|
+
from specsmith.agent.teams import list_teams
|
|
641
|
+
|
|
642
|
+
teams = list_teams()
|
|
643
|
+
self._json_ok({"teams": [t.to_dict() for t in teams]})
|
|
644
|
+
except Exception as exc: # noqa: BLE001
|
|
645
|
+
self._json_err(str(exc), code=500)
|
|
646
|
+
|
|
647
|
+
# ── MCP Servers ─────────────────────────────────────
|
|
648
|
+
elif self.path == "/api/mcp/servers":
|
|
649
|
+
try:
|
|
650
|
+
from specsmith.mcp_generator import list_mcp_servers
|
|
651
|
+
|
|
652
|
+
servers = list_mcp_servers(project_dir)
|
|
653
|
+
self._json_ok({"servers": [s.to_dict() for s in servers]})
|
|
654
|
+
except Exception as exc: # noqa: BLE001
|
|
655
|
+
self._json_err(str(exc), code=500)
|
|
656
|
+
|
|
617
657
|
# ── ESDB ──────────────────────────────────────────────
|
|
618
658
|
elif self.path == "/api/esdb/status":
|
|
619
659
|
try:
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2026 Layer1Labs / BitConcepts, LLC.
|
|
3
|
+
"""MCP Server Generator — auto-scaffold Model Context Protocol servers.
|
|
4
|
+
|
|
5
|
+
Generates Python MCP servers from natural-language tool descriptions using
|
|
6
|
+
the FastMCP pattern. Each generated server includes a `server.py`,
|
|
7
|
+
`tool_schema.json`, and `README.md`.
|
|
8
|
+
|
|
9
|
+
Usage:
|
|
10
|
+
from specsmith.mcp_generator import generate_mcp_server, list_mcp_servers
|
|
11
|
+
server = generate_mcp_server("Search USPTO patents by keyword")
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import json
|
|
17
|
+
import re
|
|
18
|
+
import uuid
|
|
19
|
+
from dataclasses import dataclass, field
|
|
20
|
+
from pathlib import Path
|
|
21
|
+
from typing import Any
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@dataclass
|
|
25
|
+
class MCPServerSpec:
|
|
26
|
+
"""Specification for a generated MCP server."""
|
|
27
|
+
|
|
28
|
+
id: str
|
|
29
|
+
name: str
|
|
30
|
+
description: str
|
|
31
|
+
tools: list[MCPToolSpec] = field(default_factory=list)
|
|
32
|
+
transport: str = "stdio" # "stdio" or "http"
|
|
33
|
+
port: int = 8100
|
|
34
|
+
|
|
35
|
+
def to_dict(self) -> dict[str, Any]:
|
|
36
|
+
return {
|
|
37
|
+
"id": self.id,
|
|
38
|
+
"name": self.name,
|
|
39
|
+
"description": self.description,
|
|
40
|
+
"tools": [t.to_dict() for t in self.tools],
|
|
41
|
+
"transport": self.transport,
|
|
42
|
+
"port": self.port,
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@dataclass
|
|
47
|
+
class MCPToolSpec:
|
|
48
|
+
"""Specification for a single MCP tool."""
|
|
49
|
+
|
|
50
|
+
name: str
|
|
51
|
+
description: str
|
|
52
|
+
input_params: dict[str, str] = field(default_factory=dict)
|
|
53
|
+
output_type: str = "text"
|
|
54
|
+
|
|
55
|
+
def to_dict(self) -> dict[str, Any]:
|
|
56
|
+
return {
|
|
57
|
+
"name": self.name,
|
|
58
|
+
"description": self.description,
|
|
59
|
+
"input_params": self.input_params,
|
|
60
|
+
"output_type": self.output_type,
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def _generate_server_id(name: str) -> str:
|
|
65
|
+
slug = re.sub(r"[^a-z0-9]+", "-", name.lower().strip())[:30]
|
|
66
|
+
return f"mcp-{slug}-{uuid.uuid4().hex[:6]}"
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def _generate_server_py(spec: MCPServerSpec) -> str:
|
|
70
|
+
"""Generate a Python MCP server file."""
|
|
71
|
+
tool_funcs = []
|
|
72
|
+
for tool in spec.tools:
|
|
73
|
+
params = ", ".join(f"{k}: str" for k in tool.input_params)
|
|
74
|
+
func = f'''
|
|
75
|
+
@mcp.tool()
|
|
76
|
+
def {tool.name}({params}) -> dict:
|
|
77
|
+
"""{tool.description}"""
|
|
78
|
+
# TODO: implement actual logic
|
|
79
|
+
return {{"result": "stub response", "tool": "{tool.name}"}}
|
|
80
|
+
'''
|
|
81
|
+
tool_funcs.append(func)
|
|
82
|
+
|
|
83
|
+
transport_line = (
|
|
84
|
+
f' mcp.run(transport="streamable-http", host="127.0.0.1", port={spec.port})'
|
|
85
|
+
if spec.transport == "http"
|
|
86
|
+
else ' mcp.run(transport="stdio")'
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
return f'''#!/usr/bin/env python3
|
|
90
|
+
# Auto-generated MCP server: {spec.name}
|
|
91
|
+
# Generated by specsmith mcp generate
|
|
92
|
+
|
|
93
|
+
from mcp.server.fastmcp import FastMCP
|
|
94
|
+
|
|
95
|
+
mcp = FastMCP("{spec.name}")
|
|
96
|
+
{"".join(tool_funcs)}
|
|
97
|
+
|
|
98
|
+
if __name__ == "__main__":
|
|
99
|
+
{transport_line}
|
|
100
|
+
'''
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def _generate_readme(spec: MCPServerSpec) -> str:
|
|
104
|
+
"""Generate README.md for the MCP server."""
|
|
105
|
+
tool_list = "\n".join(f"- **{t.name}**: {t.description}" for t in spec.tools)
|
|
106
|
+
return f"""# {spec.name}
|
|
107
|
+
|
|
108
|
+
{spec.description}
|
|
109
|
+
|
|
110
|
+
## Tools
|
|
111
|
+
|
|
112
|
+
{tool_list}
|
|
113
|
+
|
|
114
|
+
## Usage
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
# stdio mode
|
|
118
|
+
python server.py
|
|
119
|
+
|
|
120
|
+
# HTTP mode (if configured)
|
|
121
|
+
python server.py
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Configuration
|
|
125
|
+
|
|
126
|
+
Add to your MCP client config:
|
|
127
|
+
|
|
128
|
+
```json
|
|
129
|
+
{{
|
|
130
|
+
"mcpServers": {{
|
|
131
|
+
"{spec.id}": {{
|
|
132
|
+
"command": "python",
|
|
133
|
+
"args": ["server.py"]
|
|
134
|
+
}}
|
|
135
|
+
}}
|
|
136
|
+
}}
|
|
137
|
+
```
|
|
138
|
+
"""
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def generate_mcp_server(
|
|
142
|
+
tool_description: str,
|
|
143
|
+
project_dir: str = ".",
|
|
144
|
+
transport: str = "stdio",
|
|
145
|
+
port: int = 8100,
|
|
146
|
+
) -> MCPServerSpec:
|
|
147
|
+
"""Generate an MCP server from a natural-language tool description.
|
|
148
|
+
|
|
149
|
+
Creates a server directory with `server.py`, `tool_schema.json`, and `README.md`.
|
|
150
|
+
"""
|
|
151
|
+
# Parse description into server + tool spec
|
|
152
|
+
name = tool_description.strip()[:50]
|
|
153
|
+
server_id = _generate_server_id(name)
|
|
154
|
+
tool_name = re.sub(r"[^a-z0-9_]+", "_", name.lower().strip())[:40]
|
|
155
|
+
|
|
156
|
+
tool = MCPToolSpec(
|
|
157
|
+
name=tool_name,
|
|
158
|
+
description=tool_description.strip(),
|
|
159
|
+
input_params={"query": "Search query or input"},
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
spec = MCPServerSpec(
|
|
163
|
+
id=server_id,
|
|
164
|
+
name=name,
|
|
165
|
+
description=tool_description.strip(),
|
|
166
|
+
tools=[tool],
|
|
167
|
+
transport=transport,
|
|
168
|
+
port=port,
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
# Create server directory
|
|
172
|
+
server_dir = Path(project_dir).resolve() / ".specsmith" / "mcp-servers" / server_id
|
|
173
|
+
server_dir.mkdir(parents=True, exist_ok=True)
|
|
174
|
+
|
|
175
|
+
# Write files
|
|
176
|
+
(server_dir / "server.py").write_text(_generate_server_py(spec), encoding="utf-8")
|
|
177
|
+
(server_dir / "tool_schema.json").write_text(
|
|
178
|
+
json.dumps(spec.to_dict(), indent=2, ensure_ascii=False), encoding="utf-8"
|
|
179
|
+
)
|
|
180
|
+
(server_dir / "README.md").write_text(_generate_readme(spec), encoding="utf-8")
|
|
181
|
+
|
|
182
|
+
return spec
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def list_mcp_servers(project_dir: str = ".") -> list[MCPServerSpec]:
|
|
186
|
+
"""List all generated MCP servers."""
|
|
187
|
+
servers_dir = Path(project_dir).resolve() / ".specsmith" / "mcp-servers"
|
|
188
|
+
if not servers_dir.is_dir():
|
|
189
|
+
return []
|
|
190
|
+
servers: list[MCPServerSpec] = []
|
|
191
|
+
for server_dir in sorted(servers_dir.iterdir()):
|
|
192
|
+
schema_path = server_dir / "tool_schema.json"
|
|
193
|
+
if schema_path.is_file():
|
|
194
|
+
try:
|
|
195
|
+
raw = json.loads(schema_path.read_text(encoding="utf-8"))
|
|
196
|
+
servers.append(
|
|
197
|
+
MCPServerSpec(
|
|
198
|
+
id=raw.get("id", ""),
|
|
199
|
+
name=raw.get("name", ""),
|
|
200
|
+
description=raw.get("description", ""),
|
|
201
|
+
transport=raw.get("transport", "stdio"),
|
|
202
|
+
port=raw.get("port", 8100),
|
|
203
|
+
)
|
|
204
|
+
)
|
|
205
|
+
except (OSError, ValueError):
|
|
206
|
+
continue
|
|
207
|
+
return servers
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
__all__ = ["MCPServerSpec", "MCPToolSpec", "generate_mcp_server", "list_mcp_servers"]
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2026 Layer1Labs / BitConcepts, LLC.
|
|
3
|
+
"""AI-powered Skills Builder — generate agent skills from natural-language descriptions.
|
|
4
|
+
|
|
5
|
+
Skills follow the SkillNet-style ontology: each skill is a folder containing
|
|
6
|
+
a SKILL.md file with structured metadata (name, purpose, activation rules,
|
|
7
|
+
input/output schema, epistemic contract, tools used, tests required).
|
|
8
|
+
|
|
9
|
+
Usage:
|
|
10
|
+
from specsmith.skills_builder import build_skill, list_skills
|
|
11
|
+
skill = build_skill("Summarize a Python file into bullet points")
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import json
|
|
17
|
+
import re
|
|
18
|
+
import uuid
|
|
19
|
+
from dataclasses import dataclass, field
|
|
20
|
+
from pathlib import Path
|
|
21
|
+
from typing import Any
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@dataclass
|
|
25
|
+
class SkillSpec:
|
|
26
|
+
"""Structured specification for an agent skill."""
|
|
27
|
+
|
|
28
|
+
id: str
|
|
29
|
+
name: str
|
|
30
|
+
purpose: str
|
|
31
|
+
activation_rules: list[str] = field(default_factory=list)
|
|
32
|
+
input_schema: dict[str, str] = field(default_factory=dict)
|
|
33
|
+
output_schema: dict[str, str] = field(default_factory=dict)
|
|
34
|
+
epistemic_contract: str = ""
|
|
35
|
+
tools_used: list[str] = field(default_factory=list)
|
|
36
|
+
tests_required: list[str] = field(default_factory=list)
|
|
37
|
+
stop_conditions: list[str] = field(default_factory=list)
|
|
38
|
+
tags: list[str] = field(default_factory=list)
|
|
39
|
+
active: bool = False
|
|
40
|
+
|
|
41
|
+
def to_dict(self) -> dict[str, Any]:
|
|
42
|
+
return {
|
|
43
|
+
"id": self.id,
|
|
44
|
+
"name": self.name,
|
|
45
|
+
"purpose": self.purpose,
|
|
46
|
+
"activation_rules": self.activation_rules,
|
|
47
|
+
"input_schema": self.input_schema,
|
|
48
|
+
"output_schema": self.output_schema,
|
|
49
|
+
"epistemic_contract": self.epistemic_contract,
|
|
50
|
+
"tools_used": self.tools_used,
|
|
51
|
+
"tests_required": self.tests_required,
|
|
52
|
+
"stop_conditions": self.stop_conditions,
|
|
53
|
+
"tags": self.tags,
|
|
54
|
+
"active": self.active,
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
def to_markdown(self) -> str:
|
|
58
|
+
"""Generate SKILL.md content."""
|
|
59
|
+
lines = [
|
|
60
|
+
f"# {self.name}",
|
|
61
|
+
"",
|
|
62
|
+
f"**ID:** {self.id}",
|
|
63
|
+
f"**Purpose:** {self.purpose}",
|
|
64
|
+
"",
|
|
65
|
+
"## Activation Rules",
|
|
66
|
+
"",
|
|
67
|
+
]
|
|
68
|
+
for rule in self.activation_rules:
|
|
69
|
+
lines.append(f"- {rule}")
|
|
70
|
+
lines.extend(
|
|
71
|
+
[
|
|
72
|
+
"",
|
|
73
|
+
"## Input Schema",
|
|
74
|
+
"",
|
|
75
|
+
"```json",
|
|
76
|
+
json.dumps(self.input_schema, indent=2),
|
|
77
|
+
"```",
|
|
78
|
+
"",
|
|
79
|
+
"## Output Schema",
|
|
80
|
+
"",
|
|
81
|
+
"```json",
|
|
82
|
+
json.dumps(self.output_schema, indent=2),
|
|
83
|
+
"```",
|
|
84
|
+
"",
|
|
85
|
+
"## Epistemic Contract",
|
|
86
|
+
"",
|
|
87
|
+
self.epistemic_contract or "No epistemic contract defined.",
|
|
88
|
+
"",
|
|
89
|
+
"## Tools Used",
|
|
90
|
+
"",
|
|
91
|
+
]
|
|
92
|
+
)
|
|
93
|
+
for tool in self.tools_used:
|
|
94
|
+
lines.append(f"- {tool}")
|
|
95
|
+
lines.extend(["", "## Tests Required", ""])
|
|
96
|
+
for test in self.tests_required:
|
|
97
|
+
lines.append(f"- {test}")
|
|
98
|
+
lines.extend(["", "## Stop Conditions", ""])
|
|
99
|
+
for cond in self.stop_conditions:
|
|
100
|
+
lines.append(f"- {cond}")
|
|
101
|
+
return "\n".join(lines)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def _generate_skill_id(name: str) -> str:
|
|
105
|
+
slug = re.sub(r"[^a-z0-9]+", "-", name.lower().strip())[:30]
|
|
106
|
+
return f"skill-{slug}-{uuid.uuid4().hex[:6]}"
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def build_skill(
|
|
110
|
+
description: str,
|
|
111
|
+
project_dir: str = ".",
|
|
112
|
+
tags: list[str] | None = None,
|
|
113
|
+
) -> SkillSpec:
|
|
114
|
+
"""Build a skill from a natural-language description.
|
|
115
|
+
|
|
116
|
+
Currently generates a deterministic skill spec from the description.
|
|
117
|
+
When an AI provider is configured, this will use the LLM to generate
|
|
118
|
+
richer skill content.
|
|
119
|
+
"""
|
|
120
|
+
# Deterministic generation (no LLM required)
|
|
121
|
+
name = description.strip()[:60]
|
|
122
|
+
skill_id = _generate_skill_id(name)
|
|
123
|
+
|
|
124
|
+
spec = SkillSpec(
|
|
125
|
+
id=skill_id,
|
|
126
|
+
name=name,
|
|
127
|
+
purpose=description.strip(),
|
|
128
|
+
activation_rules=[f"User requests: {description[:80]}"],
|
|
129
|
+
input_schema={"task": "string", "context": "string (optional)"},
|
|
130
|
+
output_schema={"result": "string", "confidence": "number"},
|
|
131
|
+
epistemic_contract="Output must be verifiable against the input task.",
|
|
132
|
+
tools_used=["read_file", "run_shell"],
|
|
133
|
+
tests_required=[f"Verify {name} produces correct output"],
|
|
134
|
+
stop_conditions=["Confidence below 0.3", "Timeout exceeded"],
|
|
135
|
+
tags=tags or [],
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
# Save to disk
|
|
139
|
+
skill_dir = Path(project_dir).resolve() / ".specsmith" / "skills" / skill_id
|
|
140
|
+
skill_dir.mkdir(parents=True, exist_ok=True)
|
|
141
|
+
(skill_dir / "SKILL.md").write_text(spec.to_markdown(), encoding="utf-8")
|
|
142
|
+
|
|
143
|
+
# Save JSON metadata
|
|
144
|
+
(skill_dir / "skill.json").write_text(
|
|
145
|
+
json.dumps(spec.to_dict(), indent=2, ensure_ascii=False),
|
|
146
|
+
encoding="utf-8",
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
return spec
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def list_skills(project_dir: str = ".") -> list[SkillSpec]:
|
|
153
|
+
"""List all available skills in the project."""
|
|
154
|
+
skills_dir = Path(project_dir).resolve() / ".specsmith" / "skills"
|
|
155
|
+
if not skills_dir.is_dir():
|
|
156
|
+
return []
|
|
157
|
+
skills: list[SkillSpec] = []
|
|
158
|
+
for skill_dir in sorted(skills_dir.iterdir()):
|
|
159
|
+
meta_path = skill_dir / "skill.json"
|
|
160
|
+
if meta_path.is_file():
|
|
161
|
+
try:
|
|
162
|
+
raw = json.loads(meta_path.read_text(encoding="utf-8"))
|
|
163
|
+
skills.append(
|
|
164
|
+
SkillSpec(
|
|
165
|
+
id=raw.get("id", ""),
|
|
166
|
+
name=raw.get("name", ""),
|
|
167
|
+
purpose=raw.get("purpose", ""),
|
|
168
|
+
activation_rules=raw.get("activation_rules", []),
|
|
169
|
+
tools_used=raw.get("tools_used", []),
|
|
170
|
+
tags=raw.get("tags", []),
|
|
171
|
+
active=raw.get("active", False),
|
|
172
|
+
)
|
|
173
|
+
)
|
|
174
|
+
except (OSError, ValueError):
|
|
175
|
+
continue
|
|
176
|
+
return skills
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def activate_skill(skill_id: str, project_dir: str = ".") -> bool:
|
|
180
|
+
"""Activate a skill by ID."""
|
|
181
|
+
meta_path = Path(project_dir).resolve() / ".specsmith" / "skills" / skill_id / "skill.json"
|
|
182
|
+
if not meta_path.is_file():
|
|
183
|
+
return False
|
|
184
|
+
try:
|
|
185
|
+
raw = json.loads(meta_path.read_text(encoding="utf-8"))
|
|
186
|
+
raw["active"] = True
|
|
187
|
+
meta_path.write_text(json.dumps(raw, indent=2, ensure_ascii=False), encoding="utf-8")
|
|
188
|
+
return True
|
|
189
|
+
except (OSError, ValueError):
|
|
190
|
+
return False
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
__all__ = ["SkillSpec", "activate_skill", "build_skill", "list_skills"]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: specsmith
|
|
3
|
-
Version: 0.10.1.
|
|
3
|
+
Version: 0.10.1.dev295
|
|
4
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
|
|
@@ -36,6 +36,7 @@ src/specsmith/importer.py
|
|
|
36
36
|
src/specsmith/instinct.py
|
|
37
37
|
src/specsmith/languages.py
|
|
38
38
|
src/specsmith/ledger.py
|
|
39
|
+
src/specsmith/mcp_generator.py
|
|
39
40
|
src/specsmith/patent.py
|
|
40
41
|
src/specsmith/paths.py
|
|
41
42
|
src/specsmith/phase.py
|
|
@@ -52,6 +53,7 @@ src/specsmith/serve.py
|
|
|
52
53
|
src/specsmith/session.py
|
|
53
54
|
src/specsmith/session_init.py
|
|
54
55
|
src/specsmith/skills.py
|
|
56
|
+
src/specsmith/skills_builder.py
|
|
55
57
|
src/specsmith/sync.py
|
|
56
58
|
src/specsmith/tool_installer.py
|
|
57
59
|
src/specsmith/toolrules.py
|
|
@@ -220,6 +222,7 @@ tests/test_phase34_completion.py
|
|
|
220
222
|
tests/test_rate_limits.py
|
|
221
223
|
tests/test_scaffolder.py
|
|
222
224
|
tests/test_skill_marketplace.py
|
|
225
|
+
tests/test_skills_mcp.py
|
|
223
226
|
tests/test_smoke.py
|
|
224
227
|
tests/test_suggester.py
|
|
225
228
|
tests/test_tools.py
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2026 Layer1Labs / BitConcepts, LLC.
|
|
3
|
+
"""Tests for Skills Builder and MCP Server Generator."""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class TestSkillsBuilder:
|
|
11
|
+
def test_build_skill(self, tmp_path: Path) -> None:
|
|
12
|
+
from specsmith.skills_builder import build_skill
|
|
13
|
+
|
|
14
|
+
skill = build_skill("Summarize Python files into bullet points", str(tmp_path))
|
|
15
|
+
assert skill.id.startswith("skill-")
|
|
16
|
+
assert skill.name == "Summarize Python files into bullet points"
|
|
17
|
+
assert skill.purpose
|
|
18
|
+
assert len(skill.activation_rules) > 0
|
|
19
|
+
|
|
20
|
+
def test_skill_saved_to_disk(self, tmp_path: Path) -> None:
|
|
21
|
+
from specsmith.skills_builder import build_skill
|
|
22
|
+
|
|
23
|
+
skill = build_skill("Analyze code complexity", str(tmp_path))
|
|
24
|
+
skill_dir = tmp_path / ".specsmith" / "skills" / skill.id
|
|
25
|
+
assert (skill_dir / "SKILL.md").is_file()
|
|
26
|
+
assert (skill_dir / "skill.json").is_file()
|
|
27
|
+
content = (skill_dir / "SKILL.md").read_text(encoding="utf-8")
|
|
28
|
+
assert "Analyze code complexity" in content
|
|
29
|
+
|
|
30
|
+
def test_list_skills_empty(self, tmp_path: Path) -> None:
|
|
31
|
+
from specsmith.skills_builder import list_skills
|
|
32
|
+
|
|
33
|
+
assert list_skills(str(tmp_path)) == []
|
|
34
|
+
|
|
35
|
+
def test_list_skills_after_build(self, tmp_path: Path) -> None:
|
|
36
|
+
from specsmith.skills_builder import build_skill, list_skills
|
|
37
|
+
|
|
38
|
+
build_skill("Skill A", str(tmp_path))
|
|
39
|
+
build_skill("Skill B", str(tmp_path))
|
|
40
|
+
skills = list_skills(str(tmp_path))
|
|
41
|
+
assert len(skills) == 2
|
|
42
|
+
|
|
43
|
+
def test_activate_skill(self, tmp_path: Path) -> None:
|
|
44
|
+
from specsmith.skills_builder import activate_skill, build_skill, list_skills
|
|
45
|
+
|
|
46
|
+
skill = build_skill("Activatable skill", str(tmp_path))
|
|
47
|
+
assert not skill.active
|
|
48
|
+
assert activate_skill(skill.id, str(tmp_path))
|
|
49
|
+
skills = list_skills(str(tmp_path))
|
|
50
|
+
assert any(s.active for s in skills)
|
|
51
|
+
|
|
52
|
+
def test_skill_to_dict(self) -> None:
|
|
53
|
+
from specsmith.skills_builder import SkillSpec
|
|
54
|
+
|
|
55
|
+
spec = SkillSpec(id="test", name="Test", purpose="Testing")
|
|
56
|
+
d = spec.to_dict()
|
|
57
|
+
assert d["id"] == "test"
|
|
58
|
+
assert d["name"] == "Test"
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class TestMCPGenerator:
|
|
62
|
+
def test_generate_server(self, tmp_path: Path) -> None:
|
|
63
|
+
from specsmith.mcp_generator import generate_mcp_server
|
|
64
|
+
|
|
65
|
+
spec = generate_mcp_server("Search USPTO patents by keyword", str(tmp_path))
|
|
66
|
+
assert spec.id.startswith("mcp-")
|
|
67
|
+
assert len(spec.tools) == 1
|
|
68
|
+
assert spec.transport == "stdio"
|
|
69
|
+
|
|
70
|
+
def test_server_files_created(self, tmp_path: Path) -> None:
|
|
71
|
+
from specsmith.mcp_generator import generate_mcp_server
|
|
72
|
+
|
|
73
|
+
spec = generate_mcp_server("Lookup weather data", str(tmp_path))
|
|
74
|
+
server_dir = tmp_path / ".specsmith" / "mcp-servers" / spec.id
|
|
75
|
+
assert (server_dir / "server.py").is_file()
|
|
76
|
+
assert (server_dir / "tool_schema.json").is_file()
|
|
77
|
+
assert (server_dir / "README.md").is_file()
|
|
78
|
+
|
|
79
|
+
def test_server_py_contains_tool(self, tmp_path: Path) -> None:
|
|
80
|
+
from specsmith.mcp_generator import generate_mcp_server
|
|
81
|
+
|
|
82
|
+
spec = generate_mcp_server("Calculate BMI", str(tmp_path))
|
|
83
|
+
server_dir = tmp_path / ".specsmith" / "mcp-servers" / spec.id
|
|
84
|
+
content = (server_dir / "server.py").read_text(encoding="utf-8")
|
|
85
|
+
assert "FastMCP" in content
|
|
86
|
+
assert "@mcp.tool()" in content
|
|
87
|
+
|
|
88
|
+
def test_list_servers_empty(self, tmp_path: Path) -> None:
|
|
89
|
+
from specsmith.mcp_generator import list_mcp_servers
|
|
90
|
+
|
|
91
|
+
assert list_mcp_servers(str(tmp_path)) == []
|
|
92
|
+
|
|
93
|
+
def test_list_servers_after_generate(self, tmp_path: Path) -> None:
|
|
94
|
+
from specsmith.mcp_generator import generate_mcp_server, list_mcp_servers
|
|
95
|
+
|
|
96
|
+
generate_mcp_server("Tool A", str(tmp_path))
|
|
97
|
+
generate_mcp_server("Tool B", str(tmp_path))
|
|
98
|
+
servers = list_mcp_servers(str(tmp_path))
|
|
99
|
+
assert len(servers) == 2
|
|
100
|
+
|
|
101
|
+
def test_http_transport(self, tmp_path: Path) -> None:
|
|
102
|
+
from specsmith.mcp_generator import generate_mcp_server
|
|
103
|
+
|
|
104
|
+
spec = generate_mcp_server("HTTP tool", str(tmp_path), transport="http", port=9000)
|
|
105
|
+
assert spec.transport == "http"
|
|
106
|
+
assert spec.port == 9000
|
|
107
|
+
server_dir = tmp_path / ".specsmith" / "mcp-servers" / spec.id
|
|
108
|
+
content = (server_dir / "server.py").read_text(encoding="utf-8")
|
|
109
|
+
assert "streamable-http" in content
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{specsmith-0.10.1.dev293 → specsmith-0.10.1.dev295}/src/specsmith/agent/execution_profiles.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|