shackle 0.1.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.
- shackle-0.1.0/.github/workflows/ci.yml +43 -0
- shackle-0.1.0/.github/workflows/release.yml +49 -0
- shackle-0.1.0/.gitignore +39 -0
- shackle-0.1.0/CHANGELOG.md +191 -0
- shackle-0.1.0/CONTRIBUTING.md +94 -0
- shackle-0.1.0/LICENSE +113 -0
- shackle-0.1.0/PKG-INFO +199 -0
- shackle-0.1.0/README.md +147 -0
- shackle-0.1.0/docs/concepts/agents.md +93 -0
- shackle-0.1.0/docs/concepts/fleets.md +76 -0
- shackle-0.1.0/docs/concepts/tools.md +114 -0
- shackle-0.1.0/docs/concepts/voyages.md +131 -0
- shackle-0.1.0/docs/examples/index.md +41 -0
- shackle-0.1.0/docs/getting-started.md +93 -0
- shackle-0.1.0/docs/index.md +51 -0
- shackle-0.1.0/examples/01_research_writer/README.md +37 -0
- shackle-0.1.0/examples/01_research_writer/main.py +88 -0
- shackle-0.1.0/examples/01_research_writer/shackle.yaml +42 -0
- shackle-0.1.0/examples/02_parallel_analysis/README.md +38 -0
- shackle-0.1.0/examples/02_parallel_analysis/main.py +92 -0
- shackle-0.1.0/examples/02_parallel_analysis/shackle.yaml +44 -0
- shackle-0.1.0/examples/03_hierarchical_fleet/README.md +40 -0
- shackle-0.1.0/examples/03_hierarchical_fleet/main.py +113 -0
- shackle-0.1.0/examples/03_hierarchical_fleet/shackle.yaml +54 -0
- shackle-0.1.0/mkdocs.yml +58 -0
- shackle-0.1.0/pyproject.toml +100 -0
- shackle-0.1.0/src/shackle/__init__.py +77 -0
- shackle-0.1.0/src/shackle/api/__init__.py +1 -0
- shackle-0.1.0/src/shackle/api/app.py +21 -0
- shackle-0.1.0/src/shackle/api/routes.py +82 -0
- shackle-0.1.0/src/shackle/cli/__init__.py +1 -0
- shackle-0.1.0/src/shackle/cli/app.py +218 -0
- shackle-0.1.0/src/shackle/cli/output.py +96 -0
- shackle-0.1.0/src/shackle/cli/templates.py +132 -0
- shackle-0.1.0/src/shackle/config/__init__.py +6 -0
- shackle-0.1.0/src/shackle/config/schema.py +110 -0
- shackle-0.1.0/src/shackle/config/settings.py +22 -0
- shackle-0.1.0/src/shackle/config/yaml_loader.py +191 -0
- shackle-0.1.0/src/shackle/core/__init__.py +33 -0
- shackle-0.1.0/src/shackle/core/agent.py +166 -0
- shackle-0.1.0/src/shackle/core/fleet.py +39 -0
- shackle-0.1.0/src/shackle/core/memory.py +66 -0
- shackle-0.1.0/src/shackle/core/pin.py +71 -0
- shackle-0.1.0/src/shackle/core/task.py +50 -0
- shackle-0.1.0/src/shackle/core/types.py +86 -0
- shackle-0.1.0/src/shackle/core/voyage.py +251 -0
- shackle-0.1.0/src/shackle/engine/__init__.py +9 -0
- shackle-0.1.0/src/shackle/exceptions.py +29 -0
- shackle-0.1.0/src/shackle/llm/__init__.py +17 -0
- shackle-0.1.0/src/shackle/llm/provider.py +153 -0
- shackle-0.1.0/src/shackle/observability/__init__.py +12 -0
- shackle-0.1.0/src/shackle/observability/logger.py +52 -0
- shackle-0.1.0/src/shackle/observability/tracer.py +54 -0
- shackle-0.1.0/src/shackle/py.typed +0 -0
- shackle-0.1.0/src/shackle/tools/__init__.py +57 -0
- shackle-0.1.0/src/shackle/tools/base.py +162 -0
- shackle-0.1.0/src/shackle/tools/code_exec.py +70 -0
- shackle-0.1.0/src/shackle/tools/directory_list.py +68 -0
- shackle-0.1.0/src/shackle/tools/file_read.py +69 -0
- shackle-0.1.0/src/shackle/tools/file_write.py +60 -0
- shackle-0.1.0/src/shackle/tools/http_request.py +82 -0
- shackle-0.1.0/src/shackle/tools/json_parse.py +99 -0
- shackle-0.1.0/src/shackle/tools/web_search.py +96 -0
- shackle-0.1.0/tests/conftest.py +181 -0
- shackle-0.1.0/tests/test_agent.py +295 -0
- shackle-0.1.0/tests/test_api.py +63 -0
- shackle-0.1.0/tests/test_cli.py +281 -0
- shackle-0.1.0/tests/test_cli_output.py +43 -0
- shackle-0.1.0/tests/test_config.py +32 -0
- shackle-0.1.0/tests/test_exceptions.py +37 -0
- shackle-0.1.0/tests/test_fleet.py +80 -0
- shackle-0.1.0/tests/test_llm.py +191 -0
- shackle-0.1.0/tests/test_log.py +37 -0
- shackle-0.1.0/tests/test_memory.py +109 -0
- shackle-0.1.0/tests/test_pin.py +126 -0
- shackle-0.1.0/tests/test_task.py +69 -0
- shackle-0.1.0/tests/test_telemetry.py +22 -0
- shackle-0.1.0/tests/test_tool.py +162 -0
- shackle-0.1.0/tests/test_tools_base.py +110 -0
- shackle-0.1.0/tests/test_tools_code_exec.py +53 -0
- shackle-0.1.0/tests/test_tools_directory_list.py +71 -0
- shackle-0.1.0/tests/test_tools_file_read.py +61 -0
- shackle-0.1.0/tests/test_tools_file_write.py +62 -0
- shackle-0.1.0/tests/test_tools_http_request.py +96 -0
- shackle-0.1.0/tests/test_tools_json_parse.py +100 -0
- shackle-0.1.0/tests/test_tools_registry.py +75 -0
- shackle-0.1.0/tests/test_tools_web_search.py +89 -0
- shackle-0.1.0/tests/test_types.py +165 -0
- shackle-0.1.0/tests/test_voyage.py +443 -0
- shackle-0.1.0/tests/test_workflow.py +446 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [master]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [master]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
strategy:
|
|
13
|
+
matrix:
|
|
14
|
+
python-version: ["3.12", "3.13"]
|
|
15
|
+
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v4
|
|
18
|
+
|
|
19
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
20
|
+
uses: actions/setup-python@v5
|
|
21
|
+
with:
|
|
22
|
+
python-version: ${{ matrix.python-version }}
|
|
23
|
+
|
|
24
|
+
- name: Install dependencies
|
|
25
|
+
run: |
|
|
26
|
+
python -m pip install --upgrade pip
|
|
27
|
+
pip install -e ".[dev]"
|
|
28
|
+
|
|
29
|
+
- name: Lint with ruff
|
|
30
|
+
run: ruff check src/ tests/
|
|
31
|
+
|
|
32
|
+
- name: Type-check with mypy
|
|
33
|
+
run: mypy src/shackle/
|
|
34
|
+
|
|
35
|
+
- name: Run tests
|
|
36
|
+
run: pytest --cov=shackle --cov-report=xml
|
|
37
|
+
|
|
38
|
+
- name: Upload coverage
|
|
39
|
+
if: matrix.python-version == '3.12'
|
|
40
|
+
uses: codecov/codecov-action@v4
|
|
41
|
+
with:
|
|
42
|
+
file: coverage.xml
|
|
43
|
+
fail_ci_if_error: false
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
name: Release to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags: ["v*"]
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
id-token: write
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
build:
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v4
|
|
16
|
+
|
|
17
|
+
- name: Set up Python
|
|
18
|
+
uses: actions/setup-python@v5
|
|
19
|
+
with:
|
|
20
|
+
python-version: "3.12"
|
|
21
|
+
|
|
22
|
+
- name: Install build tools
|
|
23
|
+
run: |
|
|
24
|
+
python -m pip install --upgrade pip
|
|
25
|
+
pip install build
|
|
26
|
+
|
|
27
|
+
- name: Build package
|
|
28
|
+
run: python -m build
|
|
29
|
+
|
|
30
|
+
- name: Upload build artifacts
|
|
31
|
+
uses: actions/upload-artifact@v4
|
|
32
|
+
with:
|
|
33
|
+
name: dist
|
|
34
|
+
path: dist/
|
|
35
|
+
|
|
36
|
+
publish:
|
|
37
|
+
needs: build
|
|
38
|
+
runs-on: ubuntu-latest
|
|
39
|
+
environment: pypi
|
|
40
|
+
|
|
41
|
+
steps:
|
|
42
|
+
- name: Download build artifacts
|
|
43
|
+
uses: actions/download-artifact@v4
|
|
44
|
+
with:
|
|
45
|
+
name: dist
|
|
46
|
+
path: dist/
|
|
47
|
+
|
|
48
|
+
- name: Publish to PyPI
|
|
49
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
shackle-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
__pycache__/
|
|
2
|
+
*.py[cod]
|
|
3
|
+
*$py.class
|
|
4
|
+
*.egg-info/
|
|
5
|
+
dist/
|
|
6
|
+
build/
|
|
7
|
+
.eggs/
|
|
8
|
+
*.egg
|
|
9
|
+
.venv/
|
|
10
|
+
venv/
|
|
11
|
+
.env
|
|
12
|
+
.env.*
|
|
13
|
+
*.log
|
|
14
|
+
.mypy_cache/
|
|
15
|
+
.pytest_cache/
|
|
16
|
+
.ruff_cache/
|
|
17
|
+
htmlcov/
|
|
18
|
+
.coverage
|
|
19
|
+
.coverage.*
|
|
20
|
+
coverage.xml
|
|
21
|
+
*.cover
|
|
22
|
+
.tox/
|
|
23
|
+
.nox/
|
|
24
|
+
.hypothesis/
|
|
25
|
+
*.mo
|
|
26
|
+
*.pot
|
|
27
|
+
*.swp
|
|
28
|
+
*~
|
|
29
|
+
.DS_Store
|
|
30
|
+
Thumbs.db
|
|
31
|
+
.claude/
|
|
32
|
+
|
|
33
|
+
# Internal — never push to public repo
|
|
34
|
+
CLAUDE.md
|
|
35
|
+
ROADMAP.md
|
|
36
|
+
BACKLOG.md
|
|
37
|
+
docs/ideology/
|
|
38
|
+
docs/development/
|
|
39
|
+
mdfiles/
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to ShackleAI are documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.1.0] — 2026-02-18
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- MkDocs Material documentation site (`mkdocs.yml`, docs index, examples index)
|
|
12
|
+
- GitHub Actions CI workflow: test, lint, type-check on push (Python 3.12 + 3.13)
|
|
13
|
+
- GitHub Actions release workflow: publish to PyPI on tag via trusted publisher (OIDC)
|
|
14
|
+
- `docs` optional dependency group (`mkdocs-material`, `mkdocstrings[python]`)
|
|
15
|
+
- README badges (PyPI version, Python versions, license, CI status)
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
- `pyproject.toml` URLs updated to `shackle-ai/shackle` GitHub org
|
|
19
|
+
- Documentation URL changed to GitHub Pages (`shackle-ai.github.io/shackle`)
|
|
20
|
+
- README: added `init`, `validate`, `cost`, `logs` CLI commands; added Documentation section
|
|
21
|
+
- Author email updated to `useshackleai@gmail.com`
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
- 5 ruff violations in test files (unused imports, import sorting)
|
|
25
|
+
|
|
26
|
+
## [0.1.0-alpha.8] — 2026-02-18
|
|
27
|
+
|
|
28
|
+
### Added
|
|
29
|
+
- 3 complete example projects:
|
|
30
|
+
- `01_research_writer/` — sequential, 2 agents (research then write)
|
|
31
|
+
- `02_parallel_analysis/` — parallel, 3 agents (market, tech, finance)
|
|
32
|
+
- `03_hierarchical_fleet/` — hierarchical, manager + 3 workers
|
|
33
|
+
- Getting Started guide (`docs/getting-started.md`) — zero to running in 5 minutes
|
|
34
|
+
- Concepts documentation: agents.md, voyages.md, fleets.md, tools.md
|
|
35
|
+
|
|
36
|
+
### Changed
|
|
37
|
+
- Examples restructured from flat files to self-contained directories (main.py, shackle.yaml, README.md)
|
|
38
|
+
- Example 03 uses fleet/voyages YAML format with `${SHACKLE_LLM_MODEL:-gpt-4o-mini}` env var interpolation
|
|
39
|
+
|
|
40
|
+
## [0.1.0-alpha.7] — 2026-02-18
|
|
41
|
+
|
|
42
|
+
### Added
|
|
43
|
+
- Environment variable interpolation in YAML: `${VAR}` and `${VAR:-default}` syntax
|
|
44
|
+
- Fleet/voyages YAML format: `voyages` list with `cargo` (tasks), `mode`, and `fleet.name`
|
|
45
|
+
- `model` alias for `llm_model` in YAML agent definitions
|
|
46
|
+
- Pydantic schema validation for workflow YAML (`config/schema.py`)
|
|
47
|
+
- Schema validates agent references in tasks and cargo
|
|
48
|
+
- `discover_config()`: walks up directories to find `shackle.yaml`
|
|
49
|
+
- 23 new tests (321 total, 98.32% coverage)
|
|
50
|
+
|
|
51
|
+
### Changed
|
|
52
|
+
- `load_workflow()` now interpolates env vars before YAML parsing
|
|
53
|
+
- `load_workflow()` validates data against Pydantic schema before building Voyage
|
|
54
|
+
- `config/__init__.py` exports `discover_config`
|
|
55
|
+
|
|
56
|
+
## [0.1.0-alpha.6] — 2026-02-18
|
|
57
|
+
|
|
58
|
+
### Added
|
|
59
|
+
- CLI `shackle init <name>`: scaffolds new project with shackle.yaml, main.py, .env.example, README.md
|
|
60
|
+
- CLI `shackle validate <file>`: validates YAML workflow with Rich error output
|
|
61
|
+
- CLI `shackle cost <file>`: estimates LLM cost per agent with pricing table
|
|
62
|
+
- CLI `shackle logs`: displays filtered Ship's Log entries from structlog output
|
|
63
|
+
- CLI `shackle sail --voyage <name>`: named voyage selection from YAML
|
|
64
|
+
- `cli/templates.py`: scaffold templates for `shackle init`
|
|
65
|
+
- `cli/output.py`: Rich formatting helpers (agent_color, print_voyage_result, print_cost_estimate)
|
|
66
|
+
- YAML tool resolution: agents with `tools: [file_read, web_search]` get real Tool instances (CO-1)
|
|
67
|
+
- Tool execution logging: duration_s and output_len logged on every tool call (CO-2)
|
|
68
|
+
- 30 new tests (298 total, 98.26% coverage)
|
|
69
|
+
|
|
70
|
+
### Changed
|
|
71
|
+
- `cli/app.py` rewritten with all commands (init, sail, validate, cost, logs, serve, version)
|
|
72
|
+
- `config/yaml_loader.py`: `_parse_agents()` resolves tool names via registry
|
|
73
|
+
- `tools/base.py`: `execute()` logs timing with `time.monotonic()`
|
|
74
|
+
- `engine/__init__.py`: docstring clarifies orchestration lives in `voyage.py` by design (CO-3)
|
|
75
|
+
|
|
76
|
+
### Fixed
|
|
77
|
+
- CO-1: YAML loader now resolves tool names to Tool instances
|
|
78
|
+
- CO-2: Tool.execute() now logs duration and output length per CLAUDE.md rule #13
|
|
79
|
+
- CO-3: engine/ package docstring updated to explain architecture intent
|
|
80
|
+
|
|
81
|
+
## [0.1.0-alpha.5] — 2026-02-18
|
|
82
|
+
|
|
83
|
+
### Added
|
|
84
|
+
- Tool model: `requires_approval` (bool), `timeout` (int), `category` (Literal) fields
|
|
85
|
+
- Tool timeout enforcement via `asyncio.wait_for()` in `Tool.execute()`
|
|
86
|
+
- `ToolCategory` type alias for category validation
|
|
87
|
+
- 7 Tier 1 built-in tools: `file_read`, `file_write`, `web_search`, `code_execute`, `http_request`, `directory_list`, `json_parse`
|
|
88
|
+
- Path sandboxing in file tools (prevents directory traversal attacks)
|
|
89
|
+
- Tool registry: `get_builtin_tool(name)` and `list_builtin_tools()`
|
|
90
|
+
- All built-in tools have `category="builtin"`
|
|
91
|
+
- 100 new tests (268 total, 98.44% coverage)
|
|
92
|
+
|
|
93
|
+
### Changed
|
|
94
|
+
- `@tool` decorator accepts `requires_approval`, `timeout`, `category` parameters
|
|
95
|
+
- `Tool.execute()` delegates to `Tool._invoke()` for timeout wrapping
|
|
96
|
+
- `tools/__init__.py` expanded with registry and all built-in tool re-exports
|
|
97
|
+
|
|
98
|
+
## [0.1.0-alpha.4] — 2026-02-18
|
|
99
|
+
|
|
100
|
+
### Added
|
|
101
|
+
- `on_failure` strategy enforcement: `"stop"` (abort), `"retry"` (retry up to max_retries), `"skip"` (mark as skipped, continue)
|
|
102
|
+
- Task-level timeout: `asyncio.wait_for()` wraps agent execution, configurable via `task.timeout`
|
|
103
|
+
- Voyage-level timeout: wraps entire `sail()` execution, configurable via `voyage.timeout`
|
|
104
|
+
- Agent cost limit enforcement: raises `CostLimitError` when cumulative LLM cost exceeds `agent.cost_limit`
|
|
105
|
+
- `TaskStatus.SKIPPED` enum value for skip strategy
|
|
106
|
+
- `Voyage.timeout` field (0 = no limit)
|
|
107
|
+
- `Voyage._run_task()` helper: unified task execution with retry/skip/timeout handling
|
|
108
|
+
- 14 new tests (168 total, 98.90% coverage)
|
|
109
|
+
|
|
110
|
+
## [0.1.0-alpha.3] — 2026-02-18
|
|
111
|
+
|
|
112
|
+
### Changed
|
|
113
|
+
- Reorganized flat `src/shackle/` into subdirectory layout per ideology Section 9
|
|
114
|
+
- New packages: `core/`, `engine/`, `llm/`, `tools/`, `observability/`, `config/`
|
|
115
|
+
- All subpackage `__init__.py` files provide re-exports (public API unchanged)
|
|
116
|
+
- Internal imports use full subpackage paths (`from shackle.core.agent import Agent`)
|
|
117
|
+
- `from shackle import Agent, Task, Voyage` continues to work (zero breaking changes)
|
|
118
|
+
|
|
119
|
+
## [0.1.0-alpha.2] — 2026-02-18
|
|
120
|
+
|
|
121
|
+
### Added
|
|
122
|
+
- Agent: `cost_limit` (max USD per execution), `verbose` (detailed logging)
|
|
123
|
+
- Task: `timeout` (seconds before timeout), `output_schema` (Pydantic structured output)
|
|
124
|
+
- Voyage: `on_failure` (stop/retry/skip strategy), `max_retries`, `metadata`
|
|
125
|
+
- Fleet: `voyages` (available voyage names), `config` (fleet-level settings)
|
|
126
|
+
- Pin: `from_agent`, `to_agent`, `status` (pending/delivered/acknowledged), `trace_id`
|
|
127
|
+
- Memory: `backend` (local/redis/postgresql), `context_window`, `persistent`
|
|
128
|
+
- VoyageResult: `total_tokens`, `trace_id`, `pins`, `agent_logs`, `computed_total_tokens`
|
|
129
|
+
- 32 new tests (154 total, 98.81% coverage)
|
|
130
|
+
- Ruff baseline: clean (0 violations)
|
|
131
|
+
- MyPy baseline: clean (0 errors, strict mode)
|
|
132
|
+
|
|
133
|
+
### Changed
|
|
134
|
+
- Ruff config: added `runtime-evaluated-base-classes` for Pydantic, ignored B008 for Typer
|
|
135
|
+
- Import cleanup: TYPE_CHECKING blocks, `collections.abc`, `datetime.UTC`
|
|
136
|
+
|
|
137
|
+
## [0.1.0-alpha.1] — 2024-12-01
|
|
138
|
+
|
|
139
|
+
### Added
|
|
140
|
+
|
|
141
|
+
**Core Framework**
|
|
142
|
+
- `Agent` class: LLM-powered worker with role, goal, backstory, tools, and memory
|
|
143
|
+
- `Task` class: unit of work with description, expected output, context chaining
|
|
144
|
+
- `Voyage` class: orchestrator with `sail()` entry point
|
|
145
|
+
- `Fleet` class: agent group with captain/recruit/get_agent
|
|
146
|
+
- `Tool` class: wraps sync/async callables with OpenAI function-calling schema
|
|
147
|
+
- `@tool` decorator: auto-infers JSON Schema from function signatures
|
|
148
|
+
- `Pin` / `PinBoard`: voyage checkpoints for execution audit trail
|
|
149
|
+
- `Memory`: two-tier short-term + long-term agent memory with keyword search
|
|
150
|
+
|
|
151
|
+
**Orchestration**
|
|
152
|
+
- Sequential execution mode with automatic context chaining
|
|
153
|
+
- Parallel execution mode via `asyncio.gather()`
|
|
154
|
+
- Hierarchical execution mode with captain oversight
|
|
155
|
+
|
|
156
|
+
**LLM Integration**
|
|
157
|
+
- `LLMClient`: async wrapper around LiteLLM supporting 100+ providers
|
|
158
|
+
- `CostTracker`: async-safe per-call and per-voyage cost accumulation
|
|
159
|
+
- `CostLimitError`: automatic budget enforcement
|
|
160
|
+
- Retry logic: 3 attempts with exponential backoff via tenacity
|
|
161
|
+
|
|
162
|
+
**Interfaces**
|
|
163
|
+
- FastAPI REST API: `/health`, `/voyages/sail`, `/voyages/sail-from-workflow`
|
|
164
|
+
- Typer CLI: `shackle sail`, `shackle serve`, `shackle version`
|
|
165
|
+
- YAML workflow loader: declarative voyage definitions
|
|
166
|
+
|
|
167
|
+
**Observability**
|
|
168
|
+
- structlog integration: JSON and console output modes
|
|
169
|
+
- OpenTelemetry tracing: spans on LLM calls, tool execution, voyage runs
|
|
170
|
+
- Environment-based configuration via `SHACKLE_*` variables
|
|
171
|
+
|
|
172
|
+
**Quality**
|
|
173
|
+
- 122 tests, 98.77% code coverage
|
|
174
|
+
- Full LLM mocking strategy (zero real API calls in tests)
|
|
175
|
+
- PEP 561 type stubs (py.typed marker)
|
|
176
|
+
- Apache 2.0 license
|
|
177
|
+
|
|
178
|
+
**Documentation**
|
|
179
|
+
- Platform ideology document
|
|
180
|
+
- Architecture Decision Records
|
|
181
|
+
- Maritime terminology reference
|
|
182
|
+
- Stage-by-stage development documentation
|
|
183
|
+
- Competitive positioning analysis
|
|
184
|
+
- Contributing guide
|
|
185
|
+
|
|
186
|
+
### Maritime Terminology
|
|
187
|
+
- Fleet (not crew), Voyage (not workflow), Pin (not message)
|
|
188
|
+
- `voyage.sail()` (not run/execute)
|
|
189
|
+
- `DistressError` (not CrewError)
|
|
190
|
+
- Health endpoint returns `{"status": "seaworthy"}`
|
|
191
|
+
- Voyage statuses: docked, sailing, arrived, wrecked
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# Contributing to ShackleAI
|
|
2
|
+
|
|
3
|
+
Thank you for your interest in contributing to ShackleAI. This guide will help you get started.
|
|
4
|
+
|
|
5
|
+
## Development Setup
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Clone the repository
|
|
9
|
+
git clone https://github.com/shackleai/shackle.git
|
|
10
|
+
cd shackle
|
|
11
|
+
|
|
12
|
+
# Install in development mode
|
|
13
|
+
pip install -e ".[dev]"
|
|
14
|
+
|
|
15
|
+
# Verify installation
|
|
16
|
+
pytest
|
|
17
|
+
shackle version
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Code Standards
|
|
21
|
+
|
|
22
|
+
### Maritime Terminology
|
|
23
|
+
All code, docs, and user-facing text must use maritime terminology. See `docs/ideology/TERMINOLOGY.md` for the complete reference.
|
|
24
|
+
|
|
25
|
+
**Critical**: Never use "Crew" — this term belongs to CrewAI.
|
|
26
|
+
|
|
27
|
+
### Python Style
|
|
28
|
+
- Python 3.11+ required
|
|
29
|
+
- Async-first: all orchestration code must be async
|
|
30
|
+
- Pydantic v2 BaseModel for all data classes
|
|
31
|
+
- Type hints on all functions and methods
|
|
32
|
+
- Docstrings on every class and public method
|
|
33
|
+
- `__all__` exports on every module
|
|
34
|
+
|
|
35
|
+
### Linting & Formatting
|
|
36
|
+
```bash
|
|
37
|
+
ruff check src/ tests/ # Lint
|
|
38
|
+
ruff format src/ tests/ # Format
|
|
39
|
+
mypy src/shackle/ # Type check
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Testing
|
|
43
|
+
|
|
44
|
+
### Requirements
|
|
45
|
+
- **>90% test coverage** — enforced by CI
|
|
46
|
+
- Unit tests for every class and method
|
|
47
|
+
- Mock all LLM calls — never hit real APIs in tests
|
|
48
|
+
- Test failure modes, not just happy paths
|
|
49
|
+
|
|
50
|
+
### Running Tests
|
|
51
|
+
```bash
|
|
52
|
+
pytest # Full suite with coverage
|
|
53
|
+
pytest -x # Stop on first failure
|
|
54
|
+
pytest tests/test_agent.py -v # Single module
|
|
55
|
+
pytest -k "test_sail" # Filter by name
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Writing Tests
|
|
59
|
+
```python
|
|
60
|
+
# Use the fixtures from conftest.py
|
|
61
|
+
async def test_my_feature(researcher, mock_llm_client):
|
|
62
|
+
# mock_llm_client.complete is already an AsyncMock
|
|
63
|
+
task = Task(description="...", expected_output="...")
|
|
64
|
+
result = await researcher.execute(task)
|
|
65
|
+
assert result.status == TaskStatus.COMPLETED
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Pull Request Process
|
|
69
|
+
|
|
70
|
+
1. Fork the repository
|
|
71
|
+
2. Create a feature branch: `git checkout -b feature/my-feature`
|
|
72
|
+
3. Write tests first (TDD encouraged)
|
|
73
|
+
4. Implement the feature
|
|
74
|
+
5. Ensure all tests pass and coverage is >90%
|
|
75
|
+
6. Run linting: `ruff check src/ tests/`
|
|
76
|
+
7. Submit a PR with a clear description
|
|
77
|
+
|
|
78
|
+
### PR Title Convention
|
|
79
|
+
- `feat: add timeout support for tasks`
|
|
80
|
+
- `fix: correct cost tracking for parallel voyages`
|
|
81
|
+
- `docs: update terminology reference`
|
|
82
|
+
- `test: add integration tests for hierarchical mode`
|
|
83
|
+
- `refactor: move core models to core/ subpackage`
|
|
84
|
+
|
|
85
|
+
## Architecture
|
|
86
|
+
|
|
87
|
+
Before making significant changes, read:
|
|
88
|
+
- `docs/ideology/IDEOLOGY.md` — Platform vision and standards
|
|
89
|
+
- `docs/ideology/ARCHITECTURE.md` — Architecture Decision Records
|
|
90
|
+
- `docs/development/08-ALIGNMENT-GAPS.md` — Known gaps and roadmap
|
|
91
|
+
|
|
92
|
+
## Questions?
|
|
93
|
+
|
|
94
|
+
Open an issue on GitHub with the "question" label.
|
shackle-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
6
|
+
|
|
7
|
+
1. Definitions.
|
|
8
|
+
|
|
9
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
10
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
11
|
+
|
|
12
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
13
|
+
the copyright owner that is granting the License.
|
|
14
|
+
|
|
15
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
16
|
+
other entities that control, are controlled by, or are under common
|
|
17
|
+
control with that entity. For the purposes of this definition,
|
|
18
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
19
|
+
direction or management of such entity, whether by contract or
|
|
20
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
21
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
22
|
+
|
|
23
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
24
|
+
exercising permissions granted by this License.
|
|
25
|
+
|
|
26
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
27
|
+
including but not limited to software source code, documentation
|
|
28
|
+
source, and configuration files.
|
|
29
|
+
|
|
30
|
+
"Object" form shall mean any form resulting from mechanical
|
|
31
|
+
transformation or translation of a Source form, including but
|
|
32
|
+
not limited to compiled object code, generated documentation,
|
|
33
|
+
and conversions to other media types.
|
|
34
|
+
|
|
35
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
36
|
+
Object form, made available under the License, as indicated by a
|
|
37
|
+
copyright notice that is included in or attached to the work.
|
|
38
|
+
|
|
39
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
40
|
+
form, that is based on (or derived from) the Work and for which the
|
|
41
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
42
|
+
represent, as a whole, an original work of authorship.
|
|
43
|
+
|
|
44
|
+
"Contribution" shall mean any work of authorship, including
|
|
45
|
+
the original version of the Work and any modifications or additions
|
|
46
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
47
|
+
submitted to the Licensor for inclusion in the Work by the copyright
|
|
48
|
+
owner or by an individual or Legal Entity authorized to submit on
|
|
49
|
+
behalf of the copyright owner.
|
|
50
|
+
|
|
51
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
52
|
+
on behalf of whom a Contribution has been received by the Licensor and
|
|
53
|
+
subsequently incorporated within the Work.
|
|
54
|
+
|
|
55
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
56
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
57
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
58
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
59
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
60
|
+
Work and such Derivative Works in Source or Object form.
|
|
61
|
+
|
|
62
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
63
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
64
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
65
|
+
(except as stated in this section) patent license to make, have made,
|
|
66
|
+
use, offer to sell, sell, import, and otherwise transfer the Work.
|
|
67
|
+
|
|
68
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
69
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
70
|
+
modifications, and in Source or Object form, provided that You
|
|
71
|
+
meet the following conditions:
|
|
72
|
+
|
|
73
|
+
(a) You must give any other recipients of the Work or
|
|
74
|
+
Derivative Works a copy of this License; and
|
|
75
|
+
|
|
76
|
+
(b) You must cause any modified files to carry prominent notices
|
|
77
|
+
stating that You changed the files; and
|
|
78
|
+
|
|
79
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
80
|
+
that You distribute, all copyright, patent, trademark, and
|
|
81
|
+
attribution notices from the Source form of the Work; and
|
|
82
|
+
|
|
83
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
84
|
+
distribution, then any Derivative Works that You distribute must
|
|
85
|
+
include a readable copy of the attribution notices contained
|
|
86
|
+
within such NOTICE file.
|
|
87
|
+
|
|
88
|
+
5. Submission of Contributions.
|
|
89
|
+
|
|
90
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
91
|
+
names, trademarks, service marks, or product names of the Licensor.
|
|
92
|
+
|
|
93
|
+
7. Disclaimer of Warranty.
|
|
94
|
+
|
|
95
|
+
8. Limitation of Liability.
|
|
96
|
+
|
|
97
|
+
9. Accepting Warranty or Additional Liability.
|
|
98
|
+
|
|
99
|
+
END OF TERMS AND CONDITIONS
|
|
100
|
+
|
|
101
|
+
Copyright 2024 ShackleAI
|
|
102
|
+
|
|
103
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
104
|
+
you may not use this file except in compliance with the License.
|
|
105
|
+
You may obtain a copy of the License at
|
|
106
|
+
|
|
107
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
108
|
+
|
|
109
|
+
Unless required by applicable law or agreed to in writing, software
|
|
110
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
111
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
112
|
+
See the License for the specific language governing permissions and
|
|
113
|
+
limitations under the License.
|