Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,30 @@ For Python modules in this repository, treat code as the source of truth and kee
- Avoid placeholder docstrings such as "Initialize instance state" or "Build parser". Describe intent and contract instead.
- When a behavior, public API, or exception contract changes, update the corresponding docstring in the same change.

## Development Commands

| Task | Command |
|------|---------|
| Fast tests (current interpreter only) | `make test-local` |
| Full quality gate (format-check + lint + typecheck + test) | `make check` |
| Lint | `make lint` |
| Type-check | `make typecheck` |
| Format Python + Markdown | `make format` |
| Regenerate `.github/` artifacts from templates | `python3 -m vstack install` |

Test coverage is enforced at **100%** (`--cov-fail-under=100`). Every behavioral change must keep all checks green. See [CONTRIBUTING.md](../CONTRIBUTING.md) for full dev setup.

## CLI Architecture

CLI commands live in `src/vstack/cli/`, one file per command (e.g. `install.py`, `verify.py`, `validate.py`).

- Each command subclasses `BaseCommand` and implements `run(*, context: CommandContext) -> int`.
- `CommandLineInterface` (`interface.py`) is the parsing/dispatch facade — no business logic.
- `CommandService` (`service.py`) constructs and dispatches commands.
- `COMMAND_CATALOG` (`catalog.py`) is the registration point for all commands.

When adding a new CLI command: create the command class in a new file, then register it in `COMMAND_CATALOG`.

## Work Style

- Produce small, reviewable changes.
Expand Down
26 changes: 25 additions & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ on:
types:
- published

concurrency:
# Preserve release order on PyPI: publish runs execute one-by-one.
group: publish-pypi
cancel-in-progress: false

permissions:
contents: read
id-token: write
Expand All @@ -24,6 +29,8 @@ jobs:
if: github.event.release.prerelease == false
runs-on: ubuntu-latest
environment: pypi
env:
PYPI_API_TOKEN: ${{ secrets.PYPI_API_TOKEN }}

steps:
- name: Validate release tag format
Expand Down Expand Up @@ -116,5 +123,22 @@ jobs:
exit 1
fi

- name: Publish to PyPI
- name: Publish to PyPI (trusted publishing)
id: publish_trusted
continue-on-error: true
uses: pypa/gh-action-pypi-publish@release/v1

- name: Publish to PyPI (API token fallback)
if: steps.publish_trusted.outcome == 'failure' && env.PYPI_API_TOKEN != ''
uses: pypa/gh-action-pypi-publish@release/v1
Comment thread
eschaar marked this conversation as resolved.
with:
user: __token__
password: ${{ env.PYPI_API_TOKEN }}

- name: Fail when trusted publishing fails and no fallback token exists
if: steps.publish_trusted.outcome == 'failure' && env.PYPI_API_TOKEN == ''
shell: bash
run: |
echo "ERROR: trusted publishing failed and secret PYPI_API_TOKEN is not configured."
echo "Either fix PyPI trusted publisher mapping or add PYPI_API_TOKEN as a fallback."
exit 1
15 changes: 6 additions & 9 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,20 @@

## [2.0.4](https://github.com/eschaar/vstack/compare/2.0.3...2.0.4) (2026-04-28)


### Fixes

* **ci:** allow release manifest ahead of latest tag ([6e049b9](https://github.com/eschaar/vstack/commit/6e049b94f2dce202cc1805a1299e8c9df9c52d8b))

- **ci:** allow release manifest ahead of latest tag ([6e049b9](https://github.com/eschaar/vstack/commit/6e049b94f2dce202cc1805a1299e8c9df9c52d8b))

### Documentation

* **release:** restore release-please style for 2.0.x ([98d8ee1](https://github.com/eschaar/vstack/commit/98d8ee1c3e6680ab16fa07b7781bbec8db71ae3c))

- **release:** restore release-please style for 2.0.x ([98d8ee1](https://github.com/eschaar/vstack/commit/98d8ee1c3e6680ab16fa07b7781bbec8db71ae3c))

### Maintenance

* **ci:** bump automerge action dependencies ([db701d5](https://github.com/eschaar/vstack/commit/db701d5cf6ba3a370c2eb8333c49ed63176872bb))
* **ci:** tune dependabot automerge policy ([ca6155c](https://github.com/eschaar/vstack/commit/ca6155c2f117c3e9a8ebf43d7f7a926e6dce264f))
* **ci:** use app client id for release token generation ([4198797](https://github.com/eschaar/vstack/commit/41987971d521dbf8f257863b155de6c3503a6d65))
* **deps:** tune dependabot cadence and PR limits ([c3fe474](https://github.com/eschaar/vstack/commit/c3fe47498b84ecfc44c3ccd39b9c81215f00e47c))
- **ci:** bump automerge action dependencies ([db701d5](https://github.com/eschaar/vstack/commit/db701d5cf6ba3a370c2eb8333c49ed63176872bb))
- **ci:** tune dependabot automerge policy ([ca6155c](https://github.com/eschaar/vstack/commit/ca6155c2f117c3e9a8ebf43d7f7a926e6dce264f))
- **ci:** use app client id for release token generation ([4198797](https://github.com/eschaar/vstack/commit/41987971d521dbf8f257863b155de6c3503a6d65))
- **deps:** tune dependabot cadence and PR limits ([c3fe474](https://github.com/eschaar/vstack/commit/c3fe47498b84ecfc44c3ccd39b9c81215f00e47c))

## [2.0.3](https://github.com/eschaar/vstack/compare/2.0.2...2.0.3) (2026-04-28)

Expand Down
27 changes: 25 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,41 @@ pip install -U pip
pip install -e ".[dev]"
```

Run `make bootstrap` once after cloning to install all development tools.

## Development Workflow

1. Create a branch from `main`.
1. Make focused, reviewable changes.
1. Run checks locally:
1. Run the fast test suite locally before pushing:

```bash
make test-local
```

1. Alternatively, run the full quality gate (format-check + lint + typecheck + test):

```bash
make test
make check
```

1. Open a pull request with clear context.

### Available make targets

| Command | Purpose |
| ----------------- | ------------------------------------------------------- |
| `make test-local` | Run tests against the current interpreter with coverage |
| `make check` | Full quality gate: format-check, lint, typecheck, test |
| `make lint` | Lint with ruff |
| `make typecheck` | Type-check with mypy |
| `make format` | Auto-format Python and Markdown |

### Coverage requirement

Test coverage is enforced at **100%** (`--cov-fail-under=100`). Every behavioral
change must be accompanied by tests that keep all checks green.

## Commit Message Guidance

This repository uses a Conventional Commits baseline for release automation.
Expand Down
10 changes: 9 additions & 1 deletion README-pypi.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,15 @@ Profile-wide install (optional defaults for all projects):
vstack install --global
```

By default, `vstack install` preserves existing unmanaged files and local edits to tracked files by comparing the current file contents with the SHA-256 checksum recorded in `vstack.json`. Use `--adopt-name <artifact-name>` to start tracking one existing unmanaged file without overwriting it. `vstack uninstall` also preserves locally modified tracked files unless you explicitly pass `--force` or `--force-name <artifact-name>`. Use `vstack manifest status --target ...` (or `vstack status --target ...`) to see what still matches the manifest. If a legacy manifest schema is detected, run `vstack manifest upgrade --target ...` first.
By default, `vstack install` preserves existing unmanaged files and local edits to tracked files by comparing the current file contents with the SHA-256 checksum recorded in `vstack.json`. Use `--adopt-name <name>` to start tracking one existing unmanaged file without overwriting it. `vstack uninstall` also preserves locally modified tracked files unless you explicitly pass `--force` or `--force-name <name>`. Use `vstack manifest status --target ...` (or `vstack status --target ...`) to see what still matches the manifest. If a legacy manifest schema is detected, run `vstack manifest upgrade --target ...` first.

If you already have agents, skills, or other files in `.github/`, run a dry-run first to see what would be preserved before committing:

```bash
vstack install --dry-run --target /path/to/your/project
```

The summary lists preserved files as `type/name` selectors (e.g. `agent/engineer`). Resolve each conflict with `--force-name type/name` to overwrite, `--adopt-name type/name` to take ownership without overwriting, or `--force` to overwrite everything.

## Fast troubleshooting

Expand Down
28 changes: 26 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ If you see the version and no errors, your install is working.
Expected output (example):

```text
vstack 1.3.0
vstack X.Y.Z
Validation passed: no unresolved template tokens
```

Expand Down Expand Up @@ -414,7 +414,29 @@ ______________________________________________________________________
| `vstack uninstall --global` | Uninstall vstack artifacts from your VS Code profile |
| `vstack uninstall` | Uninstall from the current directory default target |

By default, `vstack install` is conservative: if a target file already exists but is not tracked by `vstack`, it is left in place. For tracked files, `--update` only rewrites artifacts whose on-disk content still matches the SHA-256 checksum of the last installed version recorded in `vstack.json`. Use `--force` to overwrite everything, `--force-name <artifact-name>` to overwrite one specific managed artifact, or `--adopt-name <artifact-name>` to start tracking one existing unmanaged file without overwriting it.
By default, `vstack install` is conservative: if a target file already exists but is not tracked by `vstack`, it is left in place. For tracked files, `--update` only rewrites artifacts whose on-disk content still matches the SHA-256 checksum of the last installed version recorded in `vstack.json`. Use `--force` to overwrite everything, `--force-name <name>` to overwrite one specific managed artifact, or `--adopt-name <name>` to start tracking one existing unmanaged file without overwriting it.

If you already have agents, skills, or other files in `.github/`, run a dry-run first to see what would be preserved before committing:

```bash
# Preview what install would do — no files are written
vstack install --dry-run --target /path/to/your/project
```

The summary shows every preserved file as a `type/name` selector (e.g. `agent/engineer`, `skill/verify`). You can then resolve each conflict selectively:

```bash
# Overwrite a specific preserved artifact
vstack install --target . --force-name agent/engineer

# Take ownership of an existing file without overwriting it
vstack install --target . --adopt-name agent/engineer

# Overwrite everything
vstack install --target . --force
```

When multiple artifact types share the same name (e.g. an `agent` and a `skill` both named `engineer`), use the `type/name` form to target one precisely.

`vstack uninstall` is conservative as well: it removes only tracked artifacts whose current checksum still matches the manifest. If a tracked file was edited locally, it is preserved unless you explicitly pass `--force` or `--force-name`. Use `vstack manifest status` (or `vstack status`) for a read-only overview of managed, modified, missing, and conflicting files.

Expand Down Expand Up @@ -475,6 +497,8 @@ flowchart TD
Action: Confirm templates exist under `src/vstack/_templates/agents/`, then run `Developer: Reload Window` in VS Code.
- Issue: Agent does not execute actions
Action: Make sure Copilot is in Agent Mode, not Ask or Edit mode.
- Issue: Files were preserved during install and vstack agents are not visible
Action: Run `vstack install --dry-run --target .` to see which files were preserved. Then use `--force-name type/name` to overwrite a specific file (e.g. `--force-name agent/engineer`), `--adopt-name type/name` to take ownership without overwriting, or `--force` to overwrite everything.

### CI parity and badges

Expand Down
3 changes: 2 additions & 1 deletion SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@

| Version | Supported |
| ------- | --------- |
| 1.x | Yes |
| 2.x | Yes |
| 1.x | No |

## Reporting a Vulnerability

Expand Down
2 changes: 1 addition & 1 deletion docs/architecture/adr/001-vscode-native-variant.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# ADR-001: VS Code–Native Variant

> Maintained by: **agents** role
> Maintained by: **architect** role

**date:** 2026-03-27\
**status:** accepted
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# ADR-002: Artifact Naming and Compatibility Policy

> Maintained by: **agents** role
> Maintained by: **architect** role

**date:** 2026-03-27\
**status:** accepted
Expand Down
2 changes: 1 addition & 1 deletion docs/architecture/adr/003-backend-first-verify.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# ADR-003: Backend-First Verification (`verify` skill)

> Maintained by: **agents** role
> Maintained by: **architect** role

**date:** 2026-03-27\
**status:** accepted
Expand Down
2 changes: 1 addition & 1 deletion docs/architecture/adr/004-option-a-to-b-pipeline.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# ADR-004: Single-Call Execution with Optional Future Orchestration

> Maintained by: **agents** role
> Maintained by: **architect** role

**date:** 2026-03-27\
**status:** accepted
Expand Down
2 changes: 1 addition & 1 deletion docs/architecture/adr/005-vscode-prompt-format.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# ADR-005: VS Code Prompt File Format

> Maintained by: **agents** role
> Maintained by: **architect** role

**date:** 2026-03-27\
**status:** superseded by ADR-009
Expand Down
2 changes: 1 addition & 1 deletion docs/architecture/adr/006-no-runtime-dependency.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# ADR-006: No Runtime Dependency on External Binaries in Skill Content

> Maintained by: **agents** role
> Maintained by: **architect** role

**date:** 2026-03-27\
**status:** accepted
Expand Down
28 changes: 14 additions & 14 deletions docs/architecture/adr/007-python-runtime.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# ADR-007: Python 3 as Canonical Runtime

> Maintained by: **agents** role
> Maintained by: **architect** role

**date:** 2026-03-27\
**status:** accepted (consolidates superseded ADR-007/ADR-008 from DECISIONS.md)
Expand All @@ -15,18 +15,17 @@ The toolchain was initially prototyped in TypeScript/Bun. In practice:

## decision

**Python 3 is the sole canonical runtime** for vstack's toolchain:
**Python 3 is the sole canonical runtime** for vstack's toolchain.
The implementation lives in the `src/vstack/` package:

- `scripts/gen_skill_docs.py` — template generator
- `scripts/validate_skills.py` — skill validation
- `scripts/skill_check.py` — health dashboard
- `test/test_skills.py` — test suite (pytest)
- `src/vstack/cli/` — CLI command handlers
- `src/vstack/artifacts/` — generic template generator
- `src/vstack/manifest/` — manifest read/write and upgrade
- `src/vstack/frontmatter/` — YAML frontmatter parsing and validation
- `tests/vstack/` — pytest test suite (100% coverage enforced)

`package.json` is kept as a convenience wrapper (`npm run build` etc.) but no
`node_modules` are installed.

Zero external Python dependencies. All scripts use stdlib only:
`re`, `json`, `pathlib`, `subprocess`, `sys`, `textwrap`.
Zero external Python dependencies at runtime. All runtime code uses stdlib only:
`re`, `json`, `pathlib`, `subprocess`, `sys`, `textwrap`, `hashlib`, `dataclasses`.

## alternatives considered

Expand All @@ -36,11 +35,12 @@ Zero external Python dependencies. All scripts use stdlib only:

## rationale

Python 3.11+ is universally available on macOS, Linux, and CI systems.
The entire toolchain is under 1000 lines of Python 3 with zero external dependencies.
Python 3.11–3.14 is the supported range, matching CI and type-checking compatibility
requirements. The package is distributed via PyPI with no runtime dependencies beyond
the Python standard library.

## impact on future orchestrated pipeline

The future orchestrated pipeline runner (`scripts/runner.py`) will be implemented in Python.
The future orchestrated pipeline runner will be implemented in Python.
`asyncio` + `subprocess` provide sufficient primitives for sequential and parallel
stage execution.
18 changes: 8 additions & 10 deletions docs/architecture/adr/008-agents-over-prompts.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# ADR-008: VS Code Agent Files Over Prompt Files

> Maintained by: **agents** role
> Maintained by: **architect** role

**date:** 2026-03-28\
**status:** accepted
Expand All @@ -18,29 +18,28 @@ provide two significant advantages:
1. **User-invocable flag**: `user-invocable: true` makes agents appear in the
Copilot agent picker.

The `prompts/` directory had 19 files and was the only VS Code–exposed surface.
The `prompts/` directory was the only VS Code–exposed surface.

## decision

Migrate from `prompts/*.prompt.md` → `.github/agents/*.agent.md`.

- Delete `prompts/` directory entirely.
- Generator (`gen_skill_docs.py`) builds `.github/agents/*.agent.md` when called with `--agents`.
- Generator produces `.github/agents/*.agent.md` from templates under `src/vstack/_templates/agents/`.
- Agent frontmatter:
```yaml
---
name: "<skill-name>"
name: "<agent-name>"
description: "<description up to 1024 chars>"
tools: [read_file, insert_edit_into_file, run_in_terminal, file_search]
tools: [read, search, edit, execute, web, vscode, todo, agent]
user-invocable: true
---
```
- `TOOL_MAP` in the generator maps template tool names to VS Code tool IDs.

## alternatives considered

1. Keep `.prompt.md` and add `.agent.md` in parallel — rejected as it duplicates
19 files and creates synchronisation overhead.
files and creates synchronisation overhead.
1. Keep `.prompt.md` only — rejected because it lacks subagent capability.

## rationale
Expand All @@ -50,6 +49,5 @@ calling each other. Migrating now keeps the groundwork low-cost.

## impact on future orchestrated pipeline

The `orchestrate` role (and eventually the pipeline runner) can invoke
`@architect`, `@tester`, etc. as named agents. This is the VS Code primitive
for multi-agent orchestration.
The pipeline can invoke `@architect`, `@tester`, etc. as named agents.
This is the VS Code primitive for multi-agent orchestration.
2 changes: 1 addition & 1 deletion docs/architecture/adr/009-role-model.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# ADR-009: 6-Role Agent Model

> Maintained by: **agents** role
> Maintained by: **architect** role

**date:** 2026-03-28\
**status:** accepted
Expand Down
Loading
Loading