Implement Mallet - a Podman-based Tekton executor as part of the chisel monorepo.
Updated Plan: ~/.config/claude/history/research/2026-02/PLAN-mallet-implementation-v2.md
Original Research: ~/.config/claude/history/research/2026-02/RESEARCH-podman-migration.md
Transform chisel into a monorepo supporting two backends:
- Chisel - Dagger backend (existing, ~8,135 LOC)
- Mallet - Podman backend (new, ~2,850 LOC to add)
Current Code Reusability: ~80% of codebase (4,810 LOC) is backend-agnostic Must Reimplement: ~20% of codebase (527 LOC) is Dagger-specific
Timeline: Week 1 Status: COMPLETE (PR #14 merged 2026-02-05) Actual LOC: +811/-164
- Create
pkg/backend/package- Define
Backendinterface inbackend.go - Define
StepRequest,StepResult,SidecarRequest,WorkspaceMounttypes - Add comprehensive godoc comments
- Define
- Create
pkg/orchestrator/package (~600 LOC moved)- Move scheduler, matrix, when, retry, timeout, steptemplate, volumes, results
- Export all functions for backend use
- Update package declarations and imports
- Create
pkg/backend/dagger/package- Refactor executor.go to implement
Backendinterface - Move sidecar.go
- All interface methods implemented
- Refactor executor.go to implement
- Update Chisel CLI
- Update imports to use new backend structure
- Verified: All 60+ tests pass, all examples work, zero regressions
Timeline: Week 2 Status: COMPLETE (2026-02-06) Actual LOC: +548 (4 commits)
- Create
cmd/mallet/directory- main.go, root.go, run.go, workspace.go
- Uses Podman backend, shares parser/types/ui with chisel
- Create stub
pkg/backend/podman/package- TDD: Tests written first (8 tests)
- All interface methods return ErrNotImplemented
- Create
Makefilewith build targets- build, build-chisel, build-mallet, test, lint, clean, install, check
- Update
.goreleaser.yamlfor multi-binary builds- Separate builds and archives for chisel and mallet
- Update root
README.mdto mention both tools - Create
cmd/mallet/README.md - Verified: Both binaries compile, mallet fails gracefully with "not implemented"
- chisel: 29MB, mallet: 15MB
- Dry-run works for both
- mallet execution: "podman backend not yet implemented"
Timeline: Weeks 3-4 Status: COMPLETE (PR #16 merged 2026-02-06) Actual LOC: +1,333/-69
- Add Podman dependencies (pure HTTP API, no CGO)
- Implement
pkg/backend/podman/client.go(~115 LOC)- Connection to Podman socket via HTTP
- Auto-detect socket path (user vs system)
- Service availability checks
- Clear error messages if service not running
- Implement
pkg/backend/podman/container.go(~479 LOC)- Container creation via REST API
- Container lifecycle: create → start → wait → logs → cleanup
- Log streaming with multiplexed stdout/stderr parsing
- Timeout handling with context cancellation
- Implement
pkg/backend/podman/executor.go(~108 LOC)- Build ContainerSpec from StepRequest
- Execute and capture output
- Return StepResult
- Timeout support
- Integration tests with real Podman (skip when unavailable)
- Verified: Can execute single-step tasks, hello-pipelinerun works (~700ms)
Timeline: Week 5 Status: COMPLETE (PR #17, 2026-02-06) Actual LOC: ~270 LOC
- Implement
pkg/backend/podman/results.go(~50 LOC)- ReadResultFromPath and CollectResults helpers
- Mount temp directory to /tekton/results
- Collect results after container execution
- Integration with orchestrator (~165 LOC changes)
- Use BuildDAG and ExecuteParallel for parallel execution
- Expand matrix tasks before building DAG
- Evaluate when conditions for conditional execution
- Pass results between dependent tasks
- Execute finally tasks after main pipeline
- Add parameter substitution (~60 LOC)
- $(params.name) with string, array, object support
- $(tasks.taskname.results.resultname) for result passing
-
$(workspaces.name.path) and $ (context.*) variables
- Verified: Full pipeline execution with result passing works
Timeline: Week 6 Status: COMPLETE (PR #18, 2026-02-06) Actual LOC: ~540 LOC
- Implement
pkg/backend/podman/sidecar.go(~285 LOC)- Pod operations (CreatePod, StartPod, StopPod, RemovePod)
- CreateContainerInPod for running containers in pods
- StartSidecar and StopSidecar implementation
- Make container command optional (use image default)
- Implement
pkg/backend/podman/cleanup.go(~150 LOC)- ResourceTracker for tracking containers, pods, volumes
- Thread-safe concurrent access
- CleanupAll with fresh context for cleanup
- RemoveVolume function
- Test sidecars, cleanup
- Verified: Sidecar lifecycle works, cleanup works
Timeline: Week 7 Status: In progress (2026-02-06) Estimated LOC: ~200 LOC
- Bug fixes from example testing
- Apply stepTemplate defaults to steps
- Handle task-level volumes with emptyDir support
- Variable substitution in workingDir
- Override entrypoint for scripts (handle images with custom entrypoints)
- Create workingDir if it doesn't exist
- Example testing (13/13 passing)
- hello-pipelinerun: PASS
- params-pipelinerun: PASS (array param expansion as designed)
- results-pipelinerun: PASS
- parallel-pipelinerun: PASS
- matrix-pipelinerun: PASS
- when-pipelinerun: PASS
- retry-pipelinerun: PASS
- timeout-pipelinerun: PASS
- steptemplate-pipelinerun: PASS
- volumes-pipelinerun: PASS
- verbose-pipelinerun: PASS
- workspace-override-pipelinerun: PASS
- sidecar-pipelinerun: PASS (pod-based execution with shared network)
- Pod-based task execution (like Tekton)
- Each task runs in its own Podman pod
- Sidecars and steps share network namespace
- Host aliases for sidecar hostname resolution (sidecars accessible by name)
- Performance optimization
- Connection pooling
- Parallel container cleanup
- Volume reuse strategies
- Documentation
- Update root
README.md(overview, when to use each tool, installation) - Create
cmd/mallet/README.md(Podman setup, troubleshooting) - Create
docs/ARCHITECTURE.md(backend abstraction design) -
Create(skipped - README covers tool selection)docs/MIGRATION.md
- Update root
- CI/CD updates
- Update
.github/workflows/ci.yaml(build/test both, mallet dry-run tests) - Update
.github/workflows/release.yaml(verify builds, pinned actions) -
.goreleaser.yamlalready configured for multi-binary builds
- Update
- Example updates
- Add comments to all YAML files
- Create
examples/README.md
- Final testing
- All examples with both tools
- Cross-platform testing
- Load testing, memory leak testing
- Verify: Mallet v0.1.0 ready for release
- Chisel continues working with zero regressions
- All 20+ example PipelineRuns execute successfully with Mallet
- Output matches Chisel (except execution timing)
- No resource leaks (containers, pods, volumes cleaned up)
- Graceful error handling and Ctrl+C cleanup
- Startup time < 2 seconds (first run)
- Execution time within 30% of Chisel for same workload
- Memory usage < 500MB for typical pipeline
- All packages have >70% test coverage
- All linters pass (
golangci-lint run) - All tests pass (
go test ./...) - Code reuse ~80% between tools
- Clear installation instructions
- Complete
--helpdocumentation - Actionable error messages
- Examples run out of the box
- Binary sizes: Chisel ~21MB, Mallet ~15MB
Build:
make build # Build both
make build-chisel # Build chisel only
make build-mallet # Build mallet onlyTest:
./chisel run examples/simple/hello-pipelinerun.yaml
./mallet run examples/simple/hello-pipelinerun.yamlArchitecture:
pkg/
types/ # Shared: Data structures
parser/ # Shared: YAML parsing
ui/ # Shared: Logging
orchestrator/ # Shared: Orchestration logic
backend/
backend.go # Interface
dagger/ # Chisel implementation
podman/ # Mallet implementation
cmd/
chisel/ # Dagger backend CLI
mallet/ # Podman backend CLI
github.com/containers/podman/v5/pkg/bindings(~3MB)github.com/containers/common/libnetwork/typesgithub.com/containers/storagegithub.com/opencontainers/runtime-spec/specs-go
dagger.io/dagger(Chisel only)github.com/spf13/cobragopkg.in/yaml.v3github.com/go-git/go-git/v5(Git resolver)github.com/google/go-containerregistry(Bundles resolver)
| Phase | Duration | LOC | Deliverable |
|---|---|---|---|
| 1. Backend Abstraction | Week 1 | ~800 | Chisel refactored |
| 2. Mallet CLI Stub | Week 2 | ~500 | Mallet compiles |
| 3. Podman Core | Weeks 3-4 | ~900 | Basic execution |
| 4. Orchestration | Week 5 | ~150 | Full pipelines |
| 5. Sidecars & Cleanup | Week 6 | ~300 | Feature parity |
| 6. Polish & Release | Week 7 | ~200 | v0.1.0 |
| Total | 7 weeks | ~2,850 | Production ready |
- Updated Plan (Feb 5, 2026):
~/.config/claude/history/research/2026-02/PLAN-mallet-implementation-v2.md - Original Research:
~/.config/claude/history/research/2026-02/RESEARCH-podman-migration.md - Current Codebase: 8,135 LOC total (80% reusable, 20% Dagger-specific)
- Estimated Completion: 2026-03-26 (7 weeks from start)