graft-dev
Git-native documentation that grafts together as your sources evolve
- Category: discovered
- Tags: github, community
- Version: 1.0.0
- Author: walid
- Downloads: 0
- GitHub stars: 1
- Updated: 2025-11-21
Download the latest version (v1.0.0) from this page.
SKILL.md
# Skill: Graft Dev
## Purpose
Implement Graft slices safely with outside-in TDD and clean architecture.
## When to Use
Activate when the user mentions:
- Implementing a vertical slice
- Working on Graft features
- Following the Graft development process
- CLI command implementation
- Testing Graft functionality
- Starting work on a slice
## Steps per Slice
### 1. Preparation
- Read slice requirements in `docs/roadmap/vertical-slices.md`
- Create todo list with TodoWrite tool tracking all implementation steps
- Review `docs/adr/0002-layered-architecture-with-separation-of-concerns.md` for architecture pattern
- Check current work log in `agent-records/work-log/<date>.md`
- Use `/slice <number>` command to set up the work session automatically
### 2. Test-First Development
- Add failing tests in `tests/` (black-box subprocess style)
- Follow existing test patterns from `tests/conftest.py`
- Tests must use `python -m graft.cli` (subprocess, not imports)
- Assert on `--json` output and exit codes
- Test error cases with helpful messages including paths
- Test edge cases: missing files, malformed YAML, missing required fields
### 3. Implementation (Layered Architecture)
Follow the layered architecture pattern from ADR-0002:
**Domain Layer** (`src/graft/domain/entities.py`):
- Immutable dataclasses with `@dataclass(frozen=True)`
- Core entities: Artifact, GraftConfig, Derivation
- Value objects: Inputs, Material, Output, Template, Policy
**Adapter Layer** (`src/graft/adapters/`):
- Protocol-based interfaces (e.g., `FileSystemPort`)
- Concrete implementations (e.g., `LocalFileSystem`, `ConfigAdapter`)
- Handle external interactions (filesystem, YAML parsing)
**Service Layer** (`src/graft/services/`):
- Use case orchestration
- Explicit dependency injection in `__init__`
- Return result objects with `.to_dict()` methods
- Business logic lives here
**CLI Layer** (`src/graft/cli.py`):
- Thin presentation layer using Typer
- Wire up dependencies at module level
- Handle output formatting (JSON vs human-readable)
- Map exceptions to proper exit codes
### 4. Validation
- Run `pytest -q` to verify all tests pass
- Test CLI manually: `python -m graft.cli <command> --json`
- Verify exit codes: 0 (success), 1 (user error), 2 (system error)
- Check JSON output matches schemas with `/schema` command
- Use `/check-contract` to verify CLI contract compliance
### 5. Documentation
- Update relevant docs in `docs/`
- Update or create schemas in `schemas/`
- Create ADR with `/adr <title>` if architectural decisions were made
- Write comprehensive work log entry with `/work-log`
## Critical Constraints
- **No side effects or network writes** — This is non-negotiable
- **No scope expansion** — Deliver only what the slice requires
- **Black-box testing** — Never import internal modules in tests
- **CLI contract stability** — All commands must support `--json`
- **Exit code compliance** — 0 for success, 1 for user error, 2 for system error
## Quality Checklist
Before marking a slice complete, verify:
- [ ] All tests pass (`pytest -q`)
- [ ] CLI returns proper exit codes (0, 1, or 2)
- [ ] JSON output matches contract and schemas
- [ ] Error messages are helpful and include paths
- [ ] Code follows layered architecture (Domain → Adapters → Services → CLI)
- [ ] Work log updated with session details
- [ ] Docs and schemas updated if needed
- [ ] No files modified in `.venv/` or `.git/`
## Common Patterns
### Service with Dependency Injection
```python
class MyService:
def __init__(self, config_adapter: ConfigAdapter, fs: FileSystemPort):
self.config_adapter = config_adapter
self.fs = fs
def execute(self, path: Path) -> MyResult:
# Business logic here
return MyResult(...)
```
### Result Object with Serialization
```python
@dataclass
class MyResult:
field1: str
field2: list
def to_dict(self) -> dict:
return {
"field1": self.field1,
"field2": self.field2
}
```
### CLI Command Structure
```python
@app.command()
def my_command(
artifact: str,
json_out: bool = typer.Option(False, "--json")
):
"""Command description."""
try:
artifact_path = _artifact_path(artifact)
result = my_service.execute(artifact_path)
if json_out:
print_json(result.to_dict())
else:
# Human-readable output
typer.echo(f"Result: {result.field1}")
except typer.BadParameter as e:
typer.echo(f"Error: {e}", err=True)
raise typer.Exit(code=1)
except Exception as e:
typer.echo(f"System error: {e}", err=True)
raise typer.Exit(code=2)
```
## Outputs
- Green tests with comprehensive coverage
- Minimal, focused implementation following layered architecture
- Updated documentation and schemas
- Work log entry with architectural notes and decisions