# Contributing (/docs/contributing)



Every shipping `@pleach/*` package ships under
**FSL-1.1-Apache-2.0** (Functional Source License with Apache 2.0
as the future license, auto-transitions to Apache 2.0 two years
after first stable publish): `@pleach/core`,
`@pleach/tools`, `@pleach/react`, `@pleach/replay`,
`@pleach/sandbox`, `@pleach/base-tools`, `@pleach/langchain`,
`@pleach/compliance`, `@pleach/eval`, `@pleach/gateway`,
`@pleach/mcp`, `@pleach/coding-agent`, `@pleach/observe`, and
`@pleach/recipes`. `@pleach/trust-pack` alone remains a reserved
npm name at `0.0.1 · UNLICENSED`.
Contributions land through the standard GitHub workflow on each
package's repository. This page is the short version; the upstream
`CONTRIBUTING.md` in each package is the canonical source.

## Where each package lives [#where-each-package-lives]

| Package                    | Repository                                                     |
| -------------------------- | -------------------------------------------------------------- |
| `@pleach/core`             | [github.com/pleachhq/core](https://github.com/pleachhq/core)   |
| `@pleach/tools`            | [github.com/pleachhq/tools](https://github.com/pleachhq/tools) |
| Other `@pleach/*` siblings | Repositories land as each SKU ships its first cut              |

Issues and PRs land on the relevant package's repository.
Cross-cutting issues (something that spans two packages, or
something about the docs site itself) land on `pleachhq/core`
with a label indicating scope.

## Filing a bug [#filing-a-bug]

A useful bug report has four sections:

1. **What you did** — minimal reproduction. A failing test case
   in `defineTool` shape is ideal; a code snippet that constructs
   a `SessionRuntime` and reproduces the issue is fine.
2. **What you expected** — what the contract says should happen.
3. **What actually happened** — observed behavior, including
   stack trace and any structured error code (1xxx–7xxx).
4. **Environment** — `@pleach/core` version, Node version,
   runtime (Node / Edge / Browser), provider, storage adapter.

Bugs without a reproduction are hard to fix. If the bug is
non-deterministic, say so explicitly — the substrate's
determinism contracts exist so non-determinism is unusual, and
calling it out helps triage.

## Proposing a feature [#proposing-a-feature]

A feature proposal is an issue with a `feature` label that
answers four questions:

1. **What problem are you solving?** Not "I want X" — "X solves
   Y, which I can't solve today because Z."
2. **What does the API surface look like?** A type signature is
   enough; a code sample is better.
3. **What does it interact with?** Which existing primitives
   (`SessionRuntime`, channels, the audit ledger) does the
   feature touch?
4. **What can't you build today without this?** Concrete; the
   substrate is intentionally small and resists scope creep.

Features that fit the existing contracts (a new built-in tool, a
new prompt section primitive, a new stream observer verdict for
an existing concern) land quickly. Features that change the
substrate's structural commitments (the lattice, the singleton
seam, the family lock) get deep design discussion first.

## Submitting a PR [#submitting-a-pr]

Three checks every PR runs through:

1. **`npm test`** — the substrate's test suite, including
   determinism fixtures.
2. **`npm run lint`** — the lint rules that enforce structural
   invariants (`lint:harness-boundary`,
   `lint:callclass-literals`, etc.).
3. **`npm run audit:*`** — the audit gates that catch
   wire-format drift and out-of-lattice edges.

A PR that fails any of these is in the wrong shape. The lint
rules are the substrate's invariants in CI form — adjust the
code, not the lint config.

### Commit shape [#commit-shape]

The upstream uses conventional commit prefixes. Common ones:

| Prefix      | Use                                 |
| ----------- | ----------------------------------- |
| `feat:`     | New feature                         |
| `fix:`      | Bug fix                             |
| `docs:`     | Documentation only                  |
| `refactor:` | Code change without behavior change |
| `perf:`     | Performance improvement             |
| `test:`     | Test-only change                    |
| `chore:`    | Build / tooling                     |

Commits are squashed at merge; the squashed message takes the
PR title's shape. Aim for one logical change per PR.

### Test coverage [#test-coverage]

New features ship with tests. The substrate's test suite has
three layers:

| Layer       | What it tests                                                 |
| ----------- | ------------------------------------------------------------- |
| Unit        | Pure functions (`computeFingerprint`, reducers, canonicalize) |
| Integration | Runtime construction + executeMessage with mock providers     |
| Determinism | Recorded fixtures replayed for byte equality                  |

A feature touching the fingerprint, the audit ledger, or the
channel reducers belongs in all three layers. A feature touching
only a peripheral surface (a new React hook, a new query helper)
belongs in unit + integration.

### Docs updates [#docs-updates]

Public-API changes land with docs updates in the same PR. The
docs site here (`pleachhq/getpleach`) is a separate repository;
small API additions land as a docs PR after the package merges,
or as a single PR that updates the package's own README +
inline JSDoc.

For substantial new surfaces (a new exported subpath, a new
plugin hook), the docs site gets a new page. The
[CLAUDE.md](https://github.com/pleachhq/getpleach/blob/main/CLAUDE.md)
in this repo documents the voice and structure conventions.

## Local development [#local-development]

```bash
git clone https://github.com/pleachhq/core
cd core
npm install
npm test
```

The substrate uses the standard npm workflow — no special build
tooling, no monorepo wrangler. The `examples/minimal-agent` and
`examples/host-adapter` directories run against the local
source.

```bash
cd examples/minimal-agent
npm install
HARNESS_MOCK_MODE=true node index.mjs
```

For changes that touch the schema bundle:

```bash
npm run schema:validate    # checks SQL bundle integrity
npm run schema:apply-test  # applies against a test DB
```

The schema bundle's additive rule (no edits to existing files,
new files only) is enforced by the validator.

## What the substrate intentionally doesn't accept [#what-the-substrate-intentionally-doesnt-accept]

A short list of patterns that consistently get rejected. Not
because the work is bad — because the substrate's contracts
foreclose them.

| Pattern                                                    | Why rejected                                              |
| ---------------------------------------------------------- | --------------------------------------------------------- |
| Async stream observers                                     | Breaks replay determinism by design                       |
| New channel kinds without commutative+associative reducers | Same                                                      |
| Out-of-lattice graph edges                                 | The lattice is what makes cost / observability structural |
| `mode: "replace"` on safety policies                       | Safety stacks append-only by contract                     |
| Storage adapters that aren't append-only for audit         | Wire-format break                                         |
| Identity-like fields in the fingerprint cache key          | Defeats interactive caching + replay                      |
| `eval("...")` or runtime code generation                   | Determinism + safety review impossible                    |

If your feature looks like one of these, the design discussion
needs to surface what you're really trying to accomplish — the
substrate likely has a different primitive for the actual goal.

## Security disclosures [#security-disclosures]

<Callout type="warn" title="Report privately, not in public issues">
  Email `getpleach@protonmail.com` for vulnerabilities. Public GitHub
  issues are the wrong channel — they tip off attackers before a fix
  ships.
</Callout>

Include:

* A description of the vulnerability.
* A reproduction (or proof-of-concept).
* Affected versions if known.
* Your preferred attribution (or anonymity).

The upstream `SECURITY.md` documents response timelines.

<Callout title="No paid bug-bounty program">
  Reports get a real response, not a payout. The substrate is small
  enough that triage and credit happen in the open.
</Callout>

## Code of conduct [#code-of-conduct]

Standard Contributor Covenant. The full text lives at
`CODE_OF_CONDUCT.md` in each repository. The short version:
be kind, don't harass, don't gatekeep, take disagreement to
substance rather than personalities.

## License acknowledgment [#license-acknowledgment]

By contributing to `@pleach/core`, you agree that your contribution
is licensed under the same FSL-1.1-Apache-2.0 the package ships
under.

No CLA. The license text in the repo is the agreement.

## Where to go next [#where-to-go-next]

<Cards>
  <Card title="Architecture" href="/docs/architecture" description="The substrate's structural commitments — what contributions need to fit." />

  <Card title="Plugin contract" href="/docs/plugin-contract" description="The contract most third-party contributions extend." />

  <Card title="Versioning policy" href="/docs/versioning" description="Semver, deprecation, pinning rules, and the FSL-1.1-Apache-2.0 license posture." />

  <Card title="FAQ" href="/docs/faq" description="Common questions — who's behind this, why FSL-1.1-Apache-2.0, where to report bugs." />
</Cards>
