Thank you for your interest in contributing to Manifesto!
- Node.js >= 24 (CI runs 24.14.0; enforced by the root
enginesfield) - pnpm 10 (declared in the root
packageManagerfield —corepack enablepicks it up automatically)
This repository is pnpm-only. Do not run npm install or commit a package-lock.json; the single source of truth for dependency resolution is pnpm-lock.yaml.
# Clone the repository
git clone https://github.com/manifesto-ai/core.git
cd core
# Install dependencies
pnpm install
# Build all packages
pnpm build
# Run tests
pnpm testWe use Conventional Commits so Release Please can generate version bumps and changelogs automatically. Avoid editing CHANGELOG.md by hand.
<type>(<scope>): <description>
[optional body]
[optional footer(s)]
| Type | Description | Changelog |
|---|---|---|
feat |
A new feature | Features |
fix |
A bug fix | Bug Fixes |
perf |
Performance improvement | Performance |
deps |
Dependency updates | Dependencies |
revert |
Revert a prior commit | Reverts |
docs |
Documentation only | Hidden |
style |
Code style (formatting, etc.) | Hidden |
refactor |
Code refactoring | Hidden |
test |
Adding tests | Hidden |
chore |
Maintenance tasks | Hidden |
ci |
CI/CD changes | Hidden |
build |
Build system changes | Hidden |
Use the package name as scope:
core- @manifesto-ai/corehost- @manifesto-ai/hostsdk- @manifesto-ai/sdkcompiler- @manifesto-ai/compilercodegen- @manifesto-ai/codegen
If a change spans multiple packages, use a comma-separated list without spaces (e.g. core,host). If the change is repo-wide (docs, tooling), omit the scope or use chore/docs without scope.
# Feature
feat(core): add explain() method for debugging
# Bug fix
fix(host): handle effect handler timeout properly
# Breaking change (add ! after type)
feat(compiler)!: change compile API signature
BREAKING CHANGE: The second parameter is now required.
# Multiple scopes
feat(core,host): add shared utility functions
# Dependency update
deps(core): bump zod to v4
# Revert
revert(core): revert "feat(core): add explain() method"- Fork the repository
- Create a feature branch (
git checkout -b feat/amazing-feature) - Make your changes
- Run tests (
pnpm test) - Commit with conventional commit message
- Push to your fork
- Open a Pull Request
Releases are automated using Release Please:
- Merge PRs to
mainwith conventional commits - Release Please creates a Release PR automatically
- Review and merge the Release PR
- GitHub Release is created automatically
- Packages are published to npm
- TypeScript strict mode
- Use
readonlyfor immutable properties - Prefer
constoverlet - Use explicit return types for public APIs
- Follow naming conventions from CLAUDE.md Section 7.3
Respect the layered architecture:
- Core (pure computation) → MUST NOT import Host, SDK runtime internals, Lineage, or Governance
- Host (execution) → MUST NOT import Governance or Lineage internals
- Lineage (continuity) → MUST NOT execute effects or evaluate authority
- Governance (legitimacy) → MUST NOT execute effects, apply patches, or seal lineage implicitly
- Runtime/SDK (composition/public API) → MUST NOT import package internals outside public/provider contracts
See CLAUDE.md Section 3 for complete details.
All code contributions MUST comply with the Manifesto Constitution (CLAUDE.md).
- Determinism — Same input MUST produce same output, always
- Snapshot as Sole Medium — All state communication through Snapshot only
- Separation of Concerns — Core computes, Host executes, Lineage records continuity, Governance authorizes legitimacy
- Immutability — Snapshots and Lineage Worlds MUST NOT mutate after creation
- Type Safety — Zero string paths in user-facing APIs
- State changes ONLY through patches (
set,unset,merge) - ALL mutations go through
apply(schema, snapshot, patches) - Snapshots are immutable;
apply()returns a new Snapshot
- Effect handlers MUST return
Patch[], never throw - Failures MUST be expressed as patches (values in Snapshot)
- Effects MUST be re-entry safe (use state guards)
Avoid these common violations (see CLAUDE.md Section 10):
| Anti-Pattern | Why It's Wrong | Correct Approach |
|---|---|---|
Direct state mutation (snapshot.state.x = 5) |
Violates immutability | Use apply() with patches |
| String paths in Builder API | No type safety | Use FieldRef (e.g., state.todos[0].title) |
| Re-entry unsafe Flows | Executes multiple times | Use state guards (onceNull, onceTrue) |
| Returning values from effects | Violates Snapshot-only rule | Write to Snapshot via patches |
| Throwing errors in Core | Core is pure | Return error values in Snapshot |
Before opening a PR, verify:
- Does this change preserve determinism? (Same input → same output)
- Does this change maintain Snapshot as sole communication medium?
- Are all state changes expressed as Patches?
- Are all errors expressed as values, not exceptions?
- Does this code import only from allowed packages?
- Is this code in the correct package for its responsibility?
- All tests pass (
pnpm test) - TypeScript compiles without errors (
pnpm build) - No
anyin public APIs - No
@ts-ignorewithout justification - Follows naming conventions (CLAUDE.md Section 7.3)
- Public APIs have TSDoc comments
- Breaking changes noted in commit message
- SPEC documents updated if behavior changes
-
pnpm docs:governance-checkpasses when ADR/SPEC/FDR docs changed
- Open a Discussion
- Check the Documentation
- Review CLAUDE.md for constitutional constraints