Skip to content

AIAG-645: v0.1.0-alpha release milestones — open source readiness, templates, CI, and changelog#1

Merged
liranhason merged 57 commits into
mainfrom
e2e-testing-plan
Apr 23, 2026
Merged

AIAG-645: v0.1.0-alpha release milestones — open source readiness, templates, CI, and changelog#1
liranhason merged 57 commits into
mainfrom
e2e-testing-plan

Conversation

@liranhason

@liranhason liranhason commented Apr 14, 2026

Copy link
Copy Markdown
Collaborator

AIAG-645

Summary

  • Completed Milestones 2–5 of the v0.1.0-alpha release plan: open source readiness, example templates, CI/publishing workflows, and changelog
  • Switched license from MIT to Apache 2.0; added CONTRIBUTING.md and SECURITY.md
  • Bundled example templates (codebase-navigator, daily-standup, release-pilot) into the CLI package
  • Fixed all ruff lint errors and updated CI action versions
  • Added CHANGELOG.md for v0.1.0-alpha; restructured release plan into M5 (polish) and M6 (go live)

Test plan

  • CI passes (ruff lint, pytest)
  • canopy create correctly bundles and provisions example templates
  • CHANGELOG.md accurately reflects all changes since initial commit
  • License headers and Apache 2.0 LICENSE file are correct

🤖 Generated with Claude Code

liranhason and others added 30 commits April 14, 2026 14:51
Add RuntimeConfig dataclass with named presets and custom env-var
overrides. CANOPY_RUNTIME env var selects the runtime (default:
claude-code). "custom" reads individual CANOPY_RUNTIME_BIN,
CANOPY_RUNTIME_RUN_FLAGS, CANOPY_RUNTIME_OUTPUT, etc. Unrecognized
values raise a helpful error listing available options.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Replace hardcoded 'claude' binary and '--name' flag with runtime.bin
and runtime.connect_flags from get_runtime_config(). Banner now shows
the actual command being used. Supports any configured runtime.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Replace hardcoded 'claude --print --output-format stream-json' with
runtime.bin + runtime.run_flags_template. Add output_format branch:
stream-json uses existing NDJSON parser with summary line; text mode
is a plain passthrough to stdout.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
- utils.py: remove hardcoded L1_FILES/L1_DIRS/L3_DIR constants;
  set_l1_readonly() now takes RuntimeConfig; resolve_template_path()
  accepts config_file parameter for runtime-specific indicator file
- create.py: pass runtime to set_l1_readonly and resolve_template_path;
  use runtime.l3_dir for memory directory initialization
- info.py: use runtime.l1_files/l1_dirs/l3_dir for layer counts;
  use runtime.config_file for identity preview

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
- Rename specs/06-claude-code-runtime.md → specs/06-runtime.md
- Rewrite doc: introduces abstract 4-point runtime interface, then
  scopes Claude Code as the reference implementation
- Add "Configuring the Runtime" section with CANOPY_RUNTIME env vars
- Add "Other Runtimes" section for custom runtime guidance
- Fix all cross-references: specs/05, specs/01, README, CLAUDE.md

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
- cli/README.md: add Runtime Configuration section with full env var
  table and custom runtime example; update Workspace Structure to
  reflect runtime-configurable L1/L3 paths
- README.md: update Docker analogy row and Status section to mention
  configurable runtime

Marks flexible-runtime plan complete.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
config.py:
- Change list[str] fields to tuple[str, ...] on frozen dataclass so
  immutability is genuine, not just field rebind protection
- Use shlex.split for CANOPY_RUNTIME_CONNECT_FLAGS (was .split())
- Validate CANOPY_RUNTIME_OUTPUT against known set; fail loudly on typos
- _parse_list → _parse_tuple, returns tuple[str, ...]
- Add import shlex; drop unused dataclasses.field

utils.py:
- Remove TYPE_CHECKING guard; use a direct top-level import of RuntimeConfig
  (no circular import exists to defend against)

run.py:
- Replace shell=True + string concat with list argv + cwd=workspace_path,
  eliminating the shell injection surface entirely
- Replace assert process.stdout is not None with an explicit RuntimeError
- Replace process.wait(timeout=) with a threading.Timer watchdog that kills
  the process if it hangs without producing output within the timeout window

info.py:
- Gate _read_mcp_servers on runtime.name == "claude-code"; other runtimes
  don't have .claude/settings.json

create.py:
- Add comment documenting the {l3_dir}/default/memory/ structure assumption

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
- Replace Olly-specific file matrix in review-agent.md with extension-based
  generic patterns; remove all Olly/Shadow/apps/api references
- Create .claude/commands/review.md with scope detection, parallel agent
  dispatch (review-agent + code-quality-specialist), and consolidated report
- Mark both plan tasks complete

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
config.py:
- Add {prompt} presence validation in CANOPY_RUNTIME_RUN_FLAGS
- Reject CANOPY_RUNTIME_BIN with path separators (/ or \)
- Add settings_file field to RuntimeConfig (claude-code: .claude/settings.json)
- Add docstring to _parse_tuple explaining CSV vs shlex semantics
- Use shlex.split for CANOPY_RUNTIME_CONNECT_FLAGS (was .split())

run.py:
- Simplify argv construction: split base flags, append prompt directly
  (eliminates shlex.quote + shlex.split double-pass quoting complexity)
- Change stderr=PIPE to stderr=sys.stderr (prevents deadlock on verbose runs)
- Wrap subprocess.Popen in try/except FileNotFoundError for clear error
- Extract _kill to module-level _kill_process function with explicit params
- Add try/except OSError in _kill_process for Ctrl-C race condition
- Remove redundant process.wait() in timeout path (already called in finally)
- Add comment about monotonic text-diff assumption in _extract_text_delta

info.py:
- Update _read_mcp_servers to accept settings_file parameter
- Remove magic-string runtime.name == "claude-code" gate; use runtime.settings_file

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Create comprehensive blackbox end-to-end tests for all CLI commands:
- Subprocess-based testing (real canopy binary invocation)
- Uses real Claude CLI as runtime for true integration testing
- 6 milestones covering ~45+ tests
- API tests marked with @pytest.mark.api for selective execution
- Tests workspace lifecycle, run/connect commands, config, error handling
- Minimal prompts to reduce API costs

Prerequisite for open-source-readiness plan.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Completes the e2e-testing plan: 14/14 tasks done.
Full suite: 51 tests pass (+ 8 api-marked skipped without key).

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…mands

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Adds a 5s sleep before each real API test call (configurable via
CANOPY_TEST_API_DELAY_SECS). Sleep fires after the skip guard so
no-key runs are unaffected.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Consolidate three identical "hello" tests into test_run_success with all
three assertions; remove artificial timeout=120 from two happy-path tests;
bump CANOPY_TEST_API_DELAY_SECS default from 5s to 10s.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Replace fixed inter-test delay (120s) with transparent exponential backoff
in run_cli: retries up to 3x (30s, 60s, 120s) when subprocess output
contains a 429 rate-limit error. Resets requires_api_key delay to 10s.
All 6 tests in test_run.py pass cleanly (~50s total, zero 429 errors).

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…template_path

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
liranhason and others added 25 commits April 19, 2026 15:37
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
….json

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…y specs

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
- LICENSE: Coralogix → Canopy Contributors
- docs/cc-stream-format.md: remove coralogix MCP server name
- CLAUDE.md: remove Shadow/Olly internal product references
- specs/07-adoption-guide.md: fix broken README link (./README.md → ../README.md)
- cli/pyproject.toml: add license, authors, keywords, classifiers, URLs
- cli/canopy_cli/py.typed: add PEP 561 marker
- .github/workflows/ci.yml: GitHub Actions lint + test on push/PR
- CONTRIBUTING.md, SECURITY.md: OSS community files
- .github/ISSUE_TEMPLATE/: bug + feature request templates
- .github/PULL_REQUEST_TEMPLATE.md: PR checklist template
- .gitignore: add context-analysis.md and scheduled_tasks.lock

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
… load_env_file, set_l1_readonly

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
… test_config.py

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
- Replace YOUR_ORG with coralogix in pyproject.toml URLs and CONTRIBUTING.md
- Gitignore .claude/agents/ and .claude/commands/ (internal dev tooling)
- Remove .claude/agents/review-agent.md and .claude/commands/review.md from tracking
- Update CLAUDE.md status: tests and CI now exist

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
- Reframe "powered by Claude Code" to "pluggable runtimes"
- Qualify all Claude Code references with "when using Claude Code" or "(default)"
- Update philosophy: "The runtime is the CPU" not "Claude Code is the runtime"
- Add runtime-agnostic language guideline to CLAUDE.md writing guidelines

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
- Add Supported Runtimes table (Claude Code default + custom)
- Rename "Reference Implementation" to "Default Runtime"
- Note isolation as a security contract for all runtimes

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
- Replace "CC runs against it" with "the agent runtime runs against it"
- Qualify .claude/ paths as Claude Code conventions
- Rename "Mapping to Claude Code Primitives" to "Mapping to Runtime Primitives"
- Generalize all CC references to "the runtime" with CC qualifiers

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…time-agnostic framing

- Replace "CC process" with "runtime process" throughout
- Replace "CC's sandboxing" with "runtime sandboxing"
- Qualify Claude Code-specific features (--resume, --max-turns)
- Generalize all unqualified Claude Code references

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…me-agnostic framing

- Adoption guide: replace CC-specific language with runtime-generic, keep CC in examples
- cli/README: soften to "agent session (Claude Code by default)"
- Templates: update all CC references to runtime-agnostic language

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
- Add 3 example templates: codebase-navigator, release-pilot, daily-standup
  - codebase-navigator: docs-as-database + skills (explain-architecture, find-examples)
  - release-pilot: multi-step skills (changelog-draft, pre-release-audit)
  - daily-standup: per-user memory (morning-briefing, standup-summary)
- Update resolve_template_path() to support bare template names and examples/ dir
- Default template changed from example-template/ to examples/codebase-navigator/
- Remove example-template/ (SRE agent) and update all references
- Add Quick Start section and template descriptions to README

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
- Move examples/ into cli/canopy_cli/examples/ so pip install includes them
- Update _find_examples_dir() to find bundled examples first, then walk-up fallback
- Add .github/workflows/publish.yml for PyPI OIDC trusted publisher on v* tags
- Verified: wheel contains all 12 template files; canopy --help works from install

Note: PyPI OIDC setup requires configuring a Trusted Publisher on pypi.org
(Settings -> Trusted Publisher -> GitHub Actions -> coralogix/canopy, workflow: publish.yml)

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Aligns with Docker (Moby) and Kubernetes licensing. Apache 2.0 includes an
explicit patent grant, which is standard for infrastructure tooling and
preferred by enterprise teams.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
- DTZ011: replace date.today() with datetime.now(tz=UTC).date() in create.py
- RUF019: replace redundant key checks with data.get() in test_create.py
- RUF059: prefix unused unpacked variables with _ in test_delete.py, test_edge_cases.py
- B011: replace assert False with raise AssertionError in test_edge_cases.py
- I001: fix unsorted imports in test_run.py
- RUF043: use raw string for regex match pattern in test_utils.py
- ci.yml: upgrade actions/checkout and astral-sh/setup-uv to v5 (Node.js 24)

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…ive)

- M5 Pre-Release Polish: CHANGELOG only (can be done anytime)
- M6 Go Live: README badges + PyPI Trusted Publisher setup + tag
- Tagging triggers PyPI — moves to M6 so it's explicit and deliberate

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
@liranhason liranhason changed the title Plan: E2E tests for Canopy CLI AIAG-645: v0.1.0-alpha release milestones — open source readiness, templates, CI, and changelog Apr 23, 2026
@liranhason
liranhason merged commit 4438fad into main Apr 23, 2026
3 checks passed
@liranhason
liranhason deleted the e2e-testing-plan branch April 23, 2026 16:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants