---
name: harness-contributing
description: Contribute a public change to Harness Anything from a GitHub issue through an isolated worktree, scoped tests, manifest-selected gates, a complete PR body, review triage, and maintainer merge. Use when a human or coding agent is preparing or updating a contribution to this repository.
---

# Harness Contributing

This is the executable contribution path for this repository. Start with a
public issue or a maintainer-approved scope, work in one isolated worktree, and
finish with a reviewable pull request. The current
[`tools/gate-manifest.json`](../../tools/gate-manifest.json),
[`package.json`](../../package.json), and
[`pull_request_template.md`](../../.github/pull_request_template.md) remain the
machine-readable authorities they describe; inspect them instead of relying on
remembered job names or template fields.

## Boundary

Use only public repository source, public issue/PR discussion, and evidence a
reviewer may see. Never copy local planning records, generated runtime state,
local agent instructions, credentials, private URLs, or absolute machine paths
into the branch or PR body. Before every commit, inspect the complete staged
diff and confirm every path belongs to the stated public scope.

The contribution scope grants authority to change the stated files and run
local checks. Push the branch or open/update its PR only when the user or
maintainer asked for that external action. No contribution grants authority to
push to `main`, bypass a gate, force-push, or merge. A maintainer owns the final
merge.

> 中文：只使用公开仓库、公开 issue/PR 和 reviewer 可见的证据。不要把本地规划、
> 运行状态、凭证、私有链接或本机绝对路径放进公开 diff 或 PR。贡献者只能提交提案，
> 不能直推或自行合入 `main`。

## Environment and worktree

Node.js 24 or newer and git are required. For a new checkout, run:

```bash
git clone https://github.com/FairladyZ625/harness-anything.git
cd harness-anything
git fetch origin
git status --short --branch
```

Run this version gate as one standalone command before `npm ci`; it exits
nonzero and prints three common activation choices when the active Node is too
old:

```bash
node -e 'const major=Number(process.versions.node.split(".")[0]); if (major < 24) { console.error([`Node.js 24+ required; found ${process.version}.`, "nvm: nvm install 24 && nvm use 24", `Homebrew node@24: brew install node@24 && export PATH="$(brew --prefix node@24)/bin:$PATH"`, "Volta: volta install node@24"].join("\n")); process.exit(1); } console.log(`Node.js ${process.version} satisfies >=24`);'
```

If it fails, use one printed line to activate Node 24, then rerun the same gate
until it exits zero. Stop if the checkout already has changes you do not own.
Do not implement on the primary checkout or shared `main`. From the primary
checkout, create exactly one task worktree from current `origin/main`:

```bash
git worktree add .worktrees/<slug> -b <branch> origin/main
cd .worktrees/<slug>
git merge-base --is-ancestor origin/main HEAD
git rev-list --count origin/main..HEAD
git log --oneline origin/main..HEAD
git status --short --branch
npm ci
```

Replace `<slug>` with a short filesystem-safe scope and `<branch>` with the
public contribution branch, such as `fix/<slug>` or `docs/<slug>`. If either
name already belongs to another worktree, choose a new name; never share that
worktree. `git merge-base --is-ancestor` must exit zero before editing. A newly
created branch should print `0` from `git rev-list` and no commit lines from
`git log`. Any listed commit is already part of the prospective
`origin/main...HEAD` PR delta: continue only when it belongs to the approved
public contribution, and later describe the whole branch delta while clearly
distinguishing those pre-existing commits from the edits made in this run.
Otherwise stop and create a clean worktree or ask the maintainer which branch
scope is intended.

Read the issue and relevant source in this worktree. State, in one sentence,
the problem, allowed change surface, excluded surface, and proof required. Ask
for a maintainer decision rather than guessing when the public issue does not
settle a load-bearing choice.

> 中文：先用单独的一条可执行命令确认 Node 24+，再从最新 `origin/main` 创建独立
> worktree；每个贡献者或 agent 使用自己的 branch/worktree。编辑前列出 ahead
> commit；它们会进入整个 PR diff，不能当作不存在。安装依赖并写清范围后再编辑。

## Make the change and test its surface

Keep the patch to the smallest coherent solution. Inspect nearby code and tests
before adding a new abstraction. Preserve unrelated changes and generated
files.

Every new Node test under `packages/` or `tools/` must:

- have a filename ending in `.test.mjs`, `.test.js`, `.test.ts`, `.spec.mjs`,
  `.spec.js`, or `.spec.ts`; and
- put exactly one of these declarations on line 1:

```js
// harness-test-tier: fast
// harness-test-tier: contract
// harness-test-tier: integration
```

Choose `fast` for pure or near-pure behavior, `contract` for public API/schema
or cross-package contracts, and `integration` for CLI, filesystem, store,
migration, or other slower behavior. The rules are enforced by
[`tools/test-tier-manifest.mjs`](../../tools/test-tier-manifest.mjs); there is no
central file list to edit.

Run changed or newly added fast tests through the repository runner:

```bash
node tools/run-node-tests.mjs --file <repo-relative-test-file>
```

Run the tests affected by the change with the repository runner. Internal server
dispatch is provided by the private `test-isolation` skill and is not part of this
public contribution skill:

```bash
node tools/run-node-tests.mjs --tier fast
```

`--changed <base>` (default `origin/main`) selects the test files the committed change
itself edits, plus the registered test files whose imports reach a changed source; the
import scan is a heuristic, so use it as the default sweep before handing off. When a
change touches a shared surface — authorization, settings, construction entry points,
protocol, or events — run the owning package's whole tier instead of the scan:

```bash
node tools/run-node-tests.mjs --tier integration --prefix packages/daemon/test
```

Exact files and the other tiers take the same selector:

```bash
node tools/run-node-tests.mjs --file tools/run-node-tests.test.mjs
```

For a docs-only change, run the closest docs checker or checker test if one exists; do
not invent a meaningless test. Always inspect the patch:

```bash
git status --short
git diff --check
git diff --stat
git diff -- <changed-paths>
```

> 中文：测试文件名必须匹配 `.test`/`.spec` 约定，首行必须且只能声明一个
> `fast|contract|integration` tier。本机先跑改动面的精确测试；交给测试服务器用
> `node tools/run-node-tests.mjs --tier fast` 运行通用本机测试。改动碰到
> 授权、settings、构造入口、协议、事件这类共享路径时，改用
> `node tools/run-node-tests.mjs --tier integration --prefix packages/<包>/test` 跑所在包整层。docs-only 改动若没有
> 对应行为测试，不要为了凑数新增无意义测试。

## Run local gates

Do not use `npm run check:local` as the contribution loop, and do not run the
full aggregate merely to approximate GitHub. GitHub CI is authoritative. The
worker stop-point command derives its cheap deterministic checks from the
current gate manifest and the complete working-tree diff:

```bash
node tools/run-manifest-gates.mjs --changed origin/main
```

Run that command before the local commit. It includes every matching gate whose
manifest entry is deterministic, local, PR-visible, and declares
`localPathGlobs`; an unscoped gate is not silently promoted into this bounded
local path. Run affected integration tests separately through the isolated test
dispatcher. Use `--workflow-job` only to reproduce or preflight a particular CI
job; workflow mode runs all selected gates and reports every failure together.

First list the current pull-request job names and tiers:

```bash
node -e 'const m=require("./tools/gate-manifest.json"); console.log([...new Set(m.gates.filter(g=>!g.aggregate).flatMap(g=>(g.executionSurfaces?.rewriteCi?.pullRequestJobs??[]).map(job=>`${g.tier}\t${job}`)))].sort().join("\n"))'
```

Then print the gate IDs, commands, and declared consumer scope behind those
jobs; use this output rather than inferring a job from its name:

```bash
node -e 'const m=require("./tools/gate-manifest.json"); for (const g of m.gates.filter(g=>!g.aggregate)) for (const job of g.executionSurfaces?.rewriteCi?.pullRequestJobs??[]) console.log(`${job}\t${g.id}\t${g.command}\t${(g.consumerScope??[]).join("; ")}`)'
```

Then run every job that matches the changed surface. Pass the merge base to the
runner so its optional manifest path declarations can narrow local commands; a
working-tree comparison includes committed, uncommitted, and untracked edits:

```bash
node tools/run-manifest-gates.mjs --workflow-job <job> --changed origin/main
npm run typecheck
```

`boundaries` is the usual job for public source, tool, and documentation
boundaries. Use the manifest's other current PR jobs when the patch touches
their surface—for example tests, package policy, dependencies/supply chain, or
the GUI. Path selection is conservative: it narrows a job only when every
changed path matches explicit `localPathGlobs`; an unclassified or mixed surface
runs the complete job. A docs-only change under `docs-release/**` selects the
three docs/release checks declared by the manifest. CI omits `--changed` and
still runs every command in every job. Record every command and result in the PR
body, including a scoped reason for anything not run.

One gate has a local credential exception. If `boundaries` reaches
`check-github-required-contexts`, the only failure that may be excluded locally
is the exact error `repository must be provided as owner/name` when no GitHub
repository/token context is available. Preserve that output and rerun the same
job with only that gate excluded:

```bash
node tools/run-manifest-gates.mjs --workflow-job boundaries --changed origin/main --exclude check-github-required-contexts
```

If that exact message is not the sole failure, do not exclude the gate. Never
treat the exclusion as a CI waiver; the required GitHub context must still pass
on the PR.

> 中文：worker 停止点统一运行 `node tools/run-manifest-gates.mjs --changed
> origin/main`；它从 manifest 中派生带 `localPathGlobs` 的本地、PR、确定性门，不维护
> 第二份清单。受影响的 integration 测试仍须经隔离派测入口单独运行。按 job 复现 CI
> 时才使用 `--workflow-job`，该模式会跑完所选门并一次报告全部失败；CI 始终全跑。
> 本地只有 `check-github-required-contexts` 的精确报错
> `repository must be provided as owner/name` 可在确认缺 GitHub 上下文后单独排除；
> 该排除不适用于 CI，也不能掩盖其他失败。

## Commit with the contributor identity

Confirm the author identity before committing:

```bash
git config --get user.name
git config --get user.email
```

If either is empty or wrong, the contributor must set their own identity before
continuing:

```bash
git config user.name "<your name>"
git config user.email "<your email>"
```

Stage only named contribution paths, recheck the staged patch, and commit:

```bash
git add <changed-paths>
git diff --cached --check
git diff --cached --stat
git diff --cached -- <changed-paths>
git commit -m "<feat|fix|refactor|docs|test|ci>: <concise English summary>"
```

Do not mention an AI author in the commit message. Use the actual human or
agent operator's configured git identity.

## Prepare the PR body

Do this after all contribution commits, because the production-delta gate
measures committed `HEAD` from its merge-base. Refresh and synchronize first,
then rerun affected tests and gates if the rebase changes the branch:

```bash
git fetch origin
date -u '+%Y-%m-%d %H:%M:%S UTC'
git rebase origin/main
git rev-parse origin/main
git merge-base origin/main HEAD
git status --short --branch
```

If the initial worktree check found approved pre-existing commits, describe the
complete `origin/main...HEAD` delta in the PR body and explicitly separate
those commits from the changes authored in the current run.

Copy the current template; never reconstruct its sections from memory:

```bash
cp .github/pull_request_template.md /tmp/harness-anything-pr-body.md
${EDITOR:-vi} /tmp/harness-anything-pr-body.md
```

Fill every uncommented section with real delivery facts. Governance
Declaration and the Dependency-Change line are required only when their
trigger applies — a manifest-derived protected surface is touched, or a
package manifest or lockfile changes; otherwise the template defaults are
complete. Do not claim CI, human review, or a test that has not happened.

Reference the public issue number in the Summary section, for example
`#1234`. Never put a private task ID, local planning ID, or private evidence
path in the public PR body. If neither `package.json` nor
`package-lock.json` changed, delete the entire `Dependency-Change:` line; do
not leave `Dependency-Change: none`. Keep and fully describe that line only
when one of those dependency files changed.

In Verification, record a command only when its exact command exited zero,
either because you ran it directly or because the manifest runner printed
that command and reported it passed. A passing current `boundaries` job
indirectly runs `npm run harness:check-import-boundaries`,
`npm run harness:scan-forbidden-symbols`,
`npm run harness:check-private-boundary`,
`npm run harness:check-implementation-contracts`,
`npm run harness:check-schema-contracts`, and
`npm run harness:check-legacy-intake-readiness`; list anything else that was
not run with a reason.

Run the authoritative production-delta calculator after all commits. It
reports the computed addition, deletion, churn, and net values from the diff
alone — no PR body declaration is involved:

```bash
node tools/gates/production-delta.mjs --base origin/main
```

Preflight the completed body through the requested environment interface,
then run the manifest's full PR-body job:

```bash
export PR_BODY="$(cat /tmp/harness-anything-pr-body.md)"
node tools/check-pr-body.mjs --env PR_BODY
export PR_BASE_SHA="$(git merge-base origin/main HEAD)"
export PR_HEAD_SHA="$(git rev-parse HEAD)"
node tools/run-manifest-gates.mjs --workflow-job pr-body-lint
unset PR_BODY PR_BASE_SHA PR_HEAD_SHA
```

[`references/example-pr-body.md`](references/example-pr-body.md) is a completed
docs-only example that exercises every section. It is a fixture, not a template:
always copy the live repository template for a real PR.

> 中文：所有 commit 完成后运行 production-delta 计算器（它只从 diff 实算，不读 PR
> 正文）。PR body 按模板填写所有未注释的节；治理声明与 `Dependency-Change:` 仅在
> 触发条件成立时必填。外部贡献者在 Summary 里引用公开 issue 号，不要放私有 ID；无
> 依赖文件变化时删除整条 `Dependency-Change:`。Verification 只记录直接通过、或由
> runner 明确打印并通过的命令，其余写明未运行与原因。不得把未发生的 CI、人工
> review 或测试写成已完成。

## Push and open the PR

This section is the external-contributor path: it uses the contributor's own
Git credentials. A different model exists for dispatched, task-bound workers in
a registered Harness workspace — they publish the branch through the daemon with
`ha task push <task-id>`, open the PR with `gh pr create --head <task-id>`, with direct-push
protection limiting any push to the task's own branch. Read hosted checks and
failure logs directly with the hosting platform CLI and your own platform
credentials. If your session runs as such a worker, use those publishing
commands instead of this section; see
[Task branch publishing](../../docs-release/operations-server-daemon.md#task-branch-publishing-and-direct-push-protection).

Push only the contribution branch to a remote where the contributor has write
access:

```bash
git push -u <write-remote> HEAD
```

With an authenticated GitHub CLI, open the PR against the canonical `main`:

```bash
gh auth status
gh pr create --repo FairladyZ625/harness-anything --base main --head <github-user>:<branch> --title "<PR title>" --body-file /tmp/harness-anything-pr-body.md
```

If the branch is in the canonical repository rather than a fork, use
`--head <branch>`. Save the PR URL. Update the body rather than replacing it
with a shorter hand-written summary when later commits change scope or delta.

## Review and merge

Watch the protected checks and read the actual failure output:

```bash
gh pr view <pr-number> --repo FairladyZ625/harness-anything --json mergeable,mergeStateStatus
gh pr checks <pr-number> --repo FairladyZ625/harness-anything --watch
gh pr view <pr-number> --repo FairladyZ625/harness-anything --comments
```

Resolve a `DIRTY`/`CONFLICTING` merge state before waiting for checks: GitHub
does not run pull_request workflows for a conflicting PR, so no checks is not
evidence of a pending run.

Triage every concrete reviewer or bot finding. Before merge, each P0/P1/P2
finding must be fixed, explained as a false positive, deferred with an owner and
reason, or left explicitly blocking. For a fix, edit the same worktree, rerun
the smallest proving test and affected manifest jobs, make another prefixed
commit, push normally, and update the PR body. Never
force-push to escape a failed check.

External contributors and their agents stop after the PR is green, current,
conflict-free, and fully reviewed. A maintainer performs the repository's normal
merge-commit path; only that maintainer may run:

```bash
gh pr merge <pr-number> --repo FairladyZ625/harness-anything --merge --delete-branch
```

Do not squash, rebase-merge, direct-push, or use an admin bypass. The
contribution is complete when GitHub reports the PR merged or closed with a
clear reason.

> 中文：逐条处理 CI、human review 和 bot comment；P0/P1/P2 必须完成 triage。
> 外部贡献者或 agent 在 PR 全绿、无冲突、review 完成后停下，由 maintainer 用普通
> merge commit 合入。不得 squash、rebase merge、直推或 admin bypass。

## Agent contributor notes

An agent follows the same path and evidence standard as a human. It must keep
the declared scope visible, preserve unrelated work, show exact commands and
results, and leave external actions such as pushing or opening a PR within the
user's granted authority. It must not report human review, Dashboard
confirmation, release readiness, or merge approval on anyone else's behalf.

Before handoff, report:

- what changed and what stayed out of scope;
- exact tests and manifest jobs run, with pass/fail results;
- commands not run and the scoped reason;
- the production delta and PR-body preflight result;
- open findings, residual risk, and the files needing human attention; and
- that merge remains maintainer-owned.

> 中文：agent 必须保留无关改动、如实报告命令结果，且不能替人声称人工确认、发布
> 就绪或合入批准。handoff 要写清改动、验证、未跑项、风险和 maintainer 合入边界。
