Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .aider.conf.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
# <!-- wellmanifest:source-links:v1 -->
# Managed standard sources: local .governance/manifest.json,
# .governance/manifest.lock.json and .governance/package-manifest.json are
# authoritative. Remote links are navigation only and are never fetched at runtime.
# Canonical instructions: https://github.com/wellmanifest/new-project/blob/main/template/files/AGENTS.template.md
# Host contract: https://github.com/wellmanifest/new-project/blob/main/governance/agent-hosts.json
# Immutable adoption/updater: https://github.com/wellmanifest/new-project/blob/main/scripts/create_adoption_lock.py
# <!-- end wellmanifest:source-links:v1 -->
# wellmanifest/new-project — fail-closed contract for aider.
# aider loads these files into every session, so the same rules apply here as
# in Cursor, Claude Code or Gemini. The pre-commit hook enforces them.
Expand All @@ -8,3 +16,7 @@ read:
# Never let the tool create commits the governance hook has not seen.
auto-commits: false
attribute-commit-message-author: true

# Bounded session controls: respect the ticket's maxActiveMinutes, create a
# checkpoint before a context or tool boundary, and leave a handoff then stop
# after a deterministic failure instead of retrying indefinitely.
19 changes: 19 additions & 0 deletions .cursor/rules/new-project-standard.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,21 @@ description: wellmanifest/new-project fail-closed ticket contract for every Curs
alwaysApply: true
---

<!-- wellmanifest:source-links:v1 -->
## Managed standard sources

Local adoption files are authoritative. Remote links are navigation only and
must not be fetched or executed at runtime.

- Local adoption manifest: [.governance/manifest.json](.governance/manifest.json)
- Local adoption lock: [.governance/manifest.lock.json](.governance/manifest.lock.json)
- Local package map: [.governance/package-manifest.json](.governance/package-manifest.json)
- Canonical instructions: [AGENTS template](https://github.com/wellmanifest/new-project/blob/main/template/files/AGENTS.template.md)
- Host contract: [agent-hosts.json](https://github.com/wellmanifest/new-project/blob/main/governance/agent-hosts.json)
- Immutable adoption/updater: [create_adoption_lock.py](https://github.com/wellmanifest/new-project/blob/main/scripts/create_adoption_lock.py)

<!-- end wellmanifest:source-links:v1 -->

# new-project standard (host-agnostic)

Before writing code in this repository:
Expand All @@ -15,3 +30,7 @@ Before writing code in this repository:
6. Run `./project/governance-check.sh` before claiming done.

The pre-commit hook rejects commits that are not bound to an `IN_PROGRESS` ticket. Do not invent ticket numbers. Do not ask the human to approve a merge; invoke validator-agent when publication needs trusted approval.

Bounded session controls: respect the ticket's `maxActiveMinutes`, create a
`checkpoint` before a context or tool boundary, and leave a `handoff` then
`stop` after a deterministic failure instead of retrying indefinitely.
19 changes: 19 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
# GitHub Copilot instructions

<!-- wellmanifest:source-links:v1 -->
## Managed standard sources

The local adoption manifest, lock and package are authoritative. Remote links
are navigation only and must not be fetched or executed at runtime.

- Local adoption manifest: [.governance/manifest.json](.governance/manifest.json)
- Local adoption lock: [.governance/manifest.lock.json](.governance/manifest.lock.json)
- Local package map: [.governance/package-manifest.json](.governance/package-manifest.json)
- Canonical instructions: [AGENTS template](https://github.com/wellmanifest/new-project/blob/main/template/files/AGENTS.template.md)
- Host contract: [agent-hosts.json](https://github.com/wellmanifest/new-project/blob/main/governance/agent-hosts.json)
- Immutable adoption/updater: [create_adoption_lock.py](https://github.com/wellmanifest/new-project/blob/main/scripts/create_adoption_lock.py)

<!-- end wellmanifest:source-links:v1 -->

This repository follows the `wellmanifest/new-project` policy-as-code standard.
Same fail-closed contract as `AGENTS.md`, `CLAUDE.md`, `GEMINI.md` and the Cursor
rule. Copilot Chat and the Copilot coding agent load this file automatically.
Expand All @@ -15,3 +30,7 @@ rule. Copilot Chat and the Copilot coding agent load this file automatically.

Suggestions that skip these steps are rejected by the pre-commit hook and by the
`governance / enforce` CI job. Markdown is not a substitute for either.

Bounded session controls: respect the ticket's `maxActiveMinutes`, create a
`checkpoint` before a context or tool boundary, and leave a `handoff` then
`stop` after a deterministic failure instead of retrying indefinitely.
72 changes: 72 additions & 0 deletions .github/workflows/new-project-branch-hygiene.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
name: new-project-branch-hygiene

# `delete_branch_on_merge` covers the merge exit. This workflow covers the
# other one: a branch whose pull request was closed without merging. Nothing
# in the toolchain removes those, and `GOV-BRANCH-LIFECYCLE-002` validates the
# repository as a whole rather than the diff under review, so a single left
# behind branch fails `governance / remote lifecycle` on *every* later pull
# request, indefinitely and through no fault of its own.
#
# Closing a pull request without merging is the explicit owner decision to
# discard the branch that the check's own remediation asks for, and GitHub
# keeps the branch restorable from the pull request page afterwards.

on:
pull_request:
types: [closed]

permissions:
contents: read

jobs:
discard-unmerged-head:
# Forks cannot be written to, and the default branch is never a head to
# discard. Both guards are cheap and keep the job from ever running where
# deleting would be wrong.
if: >-
github.event.pull_request.merged == false &&
github.event.pull_request.head.repo.full_name == github.repository &&
github.event.pull_request.head.ref != github.event.repository.default_branch
runs-on: ${{ vars.NEW_PROJECT_RUNNER_LABEL || 'ubuntu-latest' }}
permissions:
contents: write
steps:
- name: Delete the closed pull request's head branch
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
script: |
const ref = context.payload.pull_request.head.ref;

// Several pull requests may share one head branch. Deleting it
// while another is still open would break that one instead.
const owners = await github.paginate(github.rest.pulls.list, {
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open',
head: `${context.repo.owner}:${ref}`,
per_page: 100,
});
if (owners.length > 0) {
const numbers = owners.map(pull => `#${pull.number}`).join(', ');
core.info(`Kept ${ref}: still owned by ${numbers}.`);
return;
}

try {
await github.rest.git.deleteRef({
owner: context.repo.owner,
repo: context.repo.repo,
ref: `heads/${ref}`,
});
core.info(
`Deleted ${ref}. GitHub keeps it restorable from the pull request page.`,
);
} catch (error) {
// The branch is commonly gone already, because the person
// closing the pull request ticked "delete branch".
if (error.status === 404 || error.status === 422) {
core.info(`${ref} was already deleted.`);
return;
}
throw error;
}
14 changes: 9 additions & 5 deletions .github/workflows/new-project-governance.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,17 @@ jobs:
shell: bash
env:
BRANCH_LIFECYCLE_SNAPSHOT: ${{ runner.temp }}/new-project-branch-lifecycle.json
HEAD_REF: ${{ github.head_ref }}
run: |
python3 .governance/branch_lifecycle_check.py \
--snapshot "$BRANCH_LIFECYCLE_SNAPSHOT" \
--expected-repository "$GITHUB_REPOSITORY" \
arguments=(
--snapshot "$BRANCH_LIFECYCLE_SNAPSHOT"
--expected-repository "$GITHUB_REPOSITORY"
--format text
)
if [[ -n "${HEAD_REF:-}" ]]; then
arguments+=(--focus-branch "$HEAD_REF")
fi
python3 .governance/branch_lifecycle_check.py "${arguments[@]}"

enforce:
name: governance / enforce
Expand Down Expand Up @@ -110,7 +116,5 @@ jobs:
# has no range, so it validates the repository as it stands.
if [[ -n "${BASE_SHA:-}" && -n "${HEAD_SHA:-}" ]]; then
arguments+=(--base "$BASE_SHA" --head "$HEAD_SHA")
else
arguments+=(--changed-file project/TICKETS.md)
fi
python3 .governance/governance_check.py "${arguments[@]}"
44 changes: 44 additions & 0 deletions .governance/AGENT_DECISIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ observation. It grants no new Git, deployment, credential or cleanup authority.
| Same authorized scope, routine reversible fix and required tests | Proceed within the ticket. |
| Protected delivery is part of the authorized outcome | Invoke the declared validator/controller; its trusted evidence still governs merge/apply. |
| Detached snapshot shares the writer's HEAD and has no competing source delta | Preserve it; common history alone is not a second writer. |
| Branch without a worktree has every unique commit tree present in target history after divergence | Preserve the branch; managed admission can exclude that historical copy from competing deltas, without closing or discarding it. |
| Real competing dirty changes or active overlapping intent | Stop the affected write and resolve ownership; keep disjoint work progressing. |
| Missing or contradictory evidence | Report uncertainty, gather bounded observations; do not infer permission. |
| CI capacity, credentials or another external prerequisite is unavailable | Persist the exact blocker and remaining stages; do not manufacture successful checks. |
Expand All @@ -55,6 +56,49 @@ hand, add a blanket ignore, or delete evidence merely to make a gate green.

## Report the achieved stage

### Cheap preflight before expensive validation

First resolve the existing ticket and checkout, dirty paths, actual remote
publication and the next requested effect. The managed work-start query's
optional `--observe-publication` reports remote branch evidence without fetch;
its default local admission and authority boundaries remain unchanged. A local
branch ahead of `main` or its upstream can already be published on a different
remote ticket branch. Reconcile that binding, not an imaginary lost push.

Before launching a long publication suite, use the declared publisher's
read-only preflight, when available, to check ticket/branch identity, accepted
base, commit-message syntax, delivery mode, configuration and pinned tools.
Report an unavailable preflight rather than inventing a command or bypassing
the publisher. Put the cheap checks first; still run required validation and
recheck exact HEAD and fencing at the effect boundary. There is no new gate.

Report the current phase, elapsed time, evidence timestamp, exact HEAD and
next bounded action. Do not reset a retry counter or rerun an unchanged
deterministic failure as if it were progress. Cache only against all evidence
inputs; a cached test result never becomes trusted approval.

### Recovery before another attempt

Resolve the emitted diagnostic in the canonical diagnostics registry and use
its managed runbook. In particular, branch lifecycle `002` means a branch
without an open PR, whereas `003` means a missing, malformed or inconsistent
snapshot. Neither finding grants cleanup authority. Read closed PRs and exact
refs before deciding whether delivery, observation or reconciliation is needed.

Every recovery answer names the next bounded action, its existing authority,
the verification that completes it and what remains preserved if it fails.
Reuse the current ticket, checkout and pending-effect journal. A repeated
deterministic failure with unchanged inputs calls for diagnosis or a changed
prerequisite, not another identical effect, fresh ticket or empty PR. A timed-out
remote operation is observed before retry; a matching remote head means the
push is already present, not that its PR was merged.

Run the gate appropriate to the adopted delivery path; this guidance does not
create a draft-push exemption or waive a failed required check. Continue safe
diagnosis and authorized disjoint work while the dependent effect waits.

### Evidence by stage

Distinguish source edited, tests passed, commit created, PR open, trusted merge,
deployment applied and public behavior verified. Each claim needs evidence
from that stage. A local preview, HTTP 200, an unchanged version number, or a
Expand Down
50 changes: 49 additions & 1 deletion .governance/agent-hosts.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"schema": "new-project.agent-hosts/v1",
"note": "Single source of truth for the host-agnostic agent contract (AGENTS.md rule 22). scripts/agent_host_check.py proves these files are present, that the fail-closed hook is installed and active, and that the packaging metadata a repository already carries actually runs the gate. Instruction files are advisory to a model; the hook, the CI job and the packaging lifecycle bindings declared here are the parts that are not. Adding a host here without adding it to governance/package-manifest.json makes the requirement unshippable, so both change together.",
"note": "Single source of truth for the host-agnostic agent contract (AGENTS.md rule 22). scripts/agent_host_check.py proves these files are present, that the fail-closed hook is installed and active, that source links point at the local adoption contract and concrete remote standard files, that bounded-session controls are present, and that the packaging metadata a repository already carries actually runs the gate. Instruction files are advisory to a model; the hook, the CI job and the packaging lifecycle bindings declared here are the parts that are not. Adding a host here without adding it to governance/package-manifest.json makes the requirement unshippable, so both change together.",
"hook": {
"path": ".githooks/pre-commit",
"hooksPathConfig": ".githooks",
Expand Down Expand Up @@ -58,6 +58,54 @@
]
}
],
"sourceLinks": {
"schema": "new-project.agent-source-links/v1",
"authority": "Local adoption lock, local managed-file digests and protected validation are authoritative. Remote main URLs are navigation only; host instructions never fetch or execute them.",
"local": [
{"id": "hub-manifest", "path": "governance/manifest.hub.json"},
{"id": "hub-package", "path": "governance/package-manifest.json"},
{"id": "adopter-manifest", "path": ".governance/manifest.json"},
{"id": "adopter-lock", "path": ".governance/manifest.lock.json"},
{"id": "adopter-package", "path": ".governance/package-manifest.json"}
],
"remote": [
{"id": "new-project-agents", "repository": "wellmanifest/new-project", "path": "template/files/AGENTS.template.md", "url": "https://github.com/wellmanifest/new-project/blob/main/template/files/AGENTS.template.md"},
{"id": "new-project-hosts", "repository": "wellmanifest/new-project", "path": "governance/agent-hosts.json", "url": "https://github.com/wellmanifest/new-project/blob/main/governance/agent-hosts.json"},
{"id": "new-project-adoption", "repository": "wellmanifest/new-project", "path": "scripts/create_adoption_lock.py", "url": "https://github.com/wellmanifest/new-project/blob/main/scripts/create_adoption_lock.py"},
{"id": "worktrees-schema", "repository": "wellmanifest/worktrees", "path": "models/worktrees.schema.json", "url": "https://github.com/wellmanifest/worktrees/blob/main/models/worktrees.schema.json"},
{"id": "git-lifecycle-schema", "repository": "wellmanifest/git-lifecycle", "path": "standard/git-lifecycle.schema.json", "url": "https://github.com/wellmanifest/git-lifecycle/blob/main/standard/git-lifecycle.schema.json"},
{"id": "ticket-lifecycle-schema", "repository": "wellmanifest/ticket-lifecycle", "path": "standard/ticket-lifecycle.schema.json", "url": "https://github.com/wellmanifest/ticket-lifecycle/blob/main/standard/ticket-lifecycle.schema.json"},
{"id": "policy-dsl", "repository": "wellmanifest/policy-dsl", "path": "spec/POLICY_DSL.md", "url": "https://github.com/wellmanifest/policy-dsl/blob/main/spec/POLICY_DSL.md"},
{"id": "logs-contract", "repository": "wellmanifest/logs", "path": "contracts/logs.contract.json", "url": "https://github.com/wellmanifest/logs/blob/main/contracts/logs.contract.json"},
{"id": "agent-schema", "repository": "wellmanifest/agent", "path": "standard/agent.schema.json", "url": "https://github.com/wellmanifest/agent/blob/main/standard/agent.schema.json"},
{"id": "llm-policy", "repository": "wellmanifest/llm", "path": "README.md", "url": "https://github.com/wellmanifest/llm/blob/main/README.md"},
{"id": "offer-pointer", "repository": "wellmanifest/offer", "path": "README.md", "url": "https://github.com/wellmanifest/offer/blob/main/README.md"},
{"id": "brand-pointer", "repository": "wellmanifest/brand", "path": "README.md", "url": "https://github.com/wellmanifest/brand/blob/main/README.md"}
],
"requiredInEveryHost": ["new-project-agents", "new-project-hosts", "new-project-adoption"],
"requiredInAgents": ["new-project-agents", "new-project-hosts", "new-project-adoption", "worktrees-schema", "git-lifecycle-schema", "ticket-lifecycle-schema", "policy-dsl", "logs-contract", "agent-schema", "llm-policy", "offer-pointer", "brand-pointer"]
},
"anomalyChecks": {
"schema": "new-project.agent-guidance-audit/v1",
"maxInstructionBytes": 65536,
"requiredTerms": ["checkpoint", "handoff", "stop", "maxActiveMinutes"],
"contradictions": [
{
"id": "direct-default-branch-delivery",
"patterns": ["push directly to main", "never push directly to main"]
},
{
"id": "self-merge",
"patterns": ["merge directly", "never merge directly"]
}
],
"ci": {
"requiredChecksCandidates": [
"governance/required-checks.json",
".governance/required-checks.json"
]
}
},
"packaging": {
"python": {
"marker": "pyproject.toml",
Expand Down
Loading
Loading