Metadata-Version: 2.4
Name: pharnoss
Version: 0.1.0
Summary: Project-agnostic Goal B operating layer: bind sub-goals to goals via executable anchors, machine-checked.
Author: Ian Chu
License-Expression: MIT
Keywords: contract,anchors,goals,alignment,harness
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

# pharnoss

**A project-agnostic Goal B operating layer.** pharnoss (pharos, the lighthouse, +
harness) lets many contributors share one goal and contribute building blocks without
the global plan, with alignment **machine-checked** instead of argued in a PR.

It pairs with any contract-first / executable-test gate. A team's goal stays the
lighthouse; each iteration goal is written as an *executable, self-checkable anchor*
bound to a real requirement; pharnoss enforces that binding deterministically.

> pharnoss carries nothing project-specific: everything that binds it to a project lives
> in a per-project `pharnoss.toml` + an adapter doc. Drop it into any repo, point it at
> that repo's goal graph, and the gate runs.

## Install

pharnoss is pure-stdlib (Python 3.11+, **no third-party dependencies** — just `tomllib`),
so you can install it straight from GitHub with **no package index**. Pin a tag or commit
(not a branch) so you control when you upgrade.

```bash
# Run ephemerally, npx-style (no permanent install):
uvx --from git+https://github.com/IanYHChu/pharnoss@v0.2.0 pharnoss init

# Or install as a re-runnable user tool:
pipx install git+https://github.com/IanYHChu/pharnoss.git@v0.2.0

# Or into the current environment:
pip install "git+https://github.com/IanYHChu/pharnoss.git@v0.2.0"
```

Local / editable for development: `pip install -e /path/to/pharnoss`. You can also run it
without installing anything — see "No-install" below.

## Quickstart

```bash
cd your-project
pharnoss init                   # scaffold: pharnoss.toml, the skill, a starter adapter,
                                # empty anchors/claims, a GOALS.md stub
pharnoss init --example         # ...or a runnable sample (one goal + differential anchor)
# edit pharnoss.toml ([goal].source + id_pattern) and .pharnoss/adapter.md
pharnoss check                  # the alignment gate: exit 0 aligned / 1 misaligned / 2 setup
pharnoss check --report         # human view of goal -> anchor -> claim
pharnoss run                    # the reference runner: anchors as pending/frozen tests
```

`pharnoss init` is the one-command install into a project. It is idempotent (skips
existing files; `--force` to overwrite) and installs the `/pharnoss` Claude Code skill
into `.claude/skills/pharnoss/SKILL.md`.

## CLI

| Command | Does |
|---------|------|
| `pharnoss check [--config P] [--report]` | run the alignment gate (orphan / claim / manifest integrity hard; coverage advisory) |
| `pharnoss run [--config P] [--report]` | run anchors via the reference runner (pending/frozen lifecycle; exit 0/1/2) |
| `pharnoss init [--path D] [--force] [--example [ECO]]` | scaffold pharnoss into a project (`--example` adds a runnable sample) |
| `pharnoss update [--config P] [--json]` | re-sync scaffolded files to the installed pharnoss version (see Updating) |
| `pharnoss stamp [--config P]` | record the current scaffolded state as the update baseline |
| `python -m pharnoss …` | same, without the console script |

**No-install:** the repo also ships `check_alignment.py`, a stdlib shim, so a consumer
can run the gate with zero install: `python3 /path/to/pharnoss/check_alignment.py`
(handy for CI or a consumer repo that doesn't want pharnoss as a dependency).

## Updating

pharnoss has two layers, updated separately:

1. **The engine** (this package — the gate, the runner, the CLI). The package manager owns
   it; pin a newer tag:
   ```bash
   pipx upgrade pharnoss                                            # if installed via pipx
   pip install --force-reinstall "git+https://github.com/IanYHChu/pharnoss.git@v0.3.0"
   ```
2. **The scaffolded files** that live inside your repo — chiefly the `/pharnoss` skill. These
   go stale when the engine moves on. `pharnoss update` re-syncs them **without clobbering
   your work**:
   ```bash
   pharnoss update          # in your project, after upgrading the engine
   ```
   It records a base in `.pharnoss/install.json` (the pharnoss version that last scaffolded
   the project + a hash per tracked file) so it can tell a pristine file (safe to overwrite)
   from one you edited. Pristine skill files are overwritten to the latest; a file you
   customized is reported as `needs_merge` and left untouched; new optional `pharnoss.toml`
   keys are reported, never force-written. Your goal graph, anchors, claims, and adapter prose
   are never overwritten.

   Because pharnoss is a Claude Code extension, the merge of customized files is LLM-assisted:
   run **`/pharnoss update`** in Claude Code and the skill reads the report plus the
   maintainer-authored upgrade notes for the version span and merges new capability into your
   files additively, showing you a diff before finalizing.

> **For maintainers:** any release that changes a scaffolded file (the skill, the config
> schema, or the adapter template) ships an upgrade note under `pharnoss/upgrades/<version>.md`.
> Keep config changes **additive and backward-compatible** (new keys optional with a default,
> no renames) so an update introduces capability rather than forcing a migration.

## What pharnoss owns vs what your project owns

pharnoss owns the **project-agnostic core**: the manifest + claim schemas, the alignment
gate (`pharnoss/align.py`), the `/pharnoss` skill (`pharnoss/skill/SKILL.md`), and the
lifecycle (`pending` → `frozen` = promote; the ratchet; informant-vs-judge). The default
status vocabulary is `pending`/`frozen` (override via `[anchors].statuses`).

Your project owns the **binding** (`pharnoss.toml`): the goal graph and its id format
(`[goal]`), the anchor manifest, the executable runner (`[runner]` — pharnoss ships a
*replaceable* reference runner, `pharnoss run`, or point it at your own: pytest, make,
cargo, …), and the adapter doc (`[adapter].doc`) with the project-specific HOW. See
`pharnoss.example.toml` for the full schema.

## The alignment gate

`check` binds three artifacts named in `pharnoss.toml`: the goal graph (`[goal].source`),
the anchor manifest (`[anchors].manifest`, each anchor names a `parent` goal id), and the
claim ledger (`[claims].file`). It finds `pharnoss.toml` in the current directory or any
parent unless `--config` is given. ORPHAN anchor (parent not a real goal) and CLAIM
integrity hard-fail (exit 1); goal COVERAGE is advisory — a goal with no anchor is a
backfill worklist, not a failure.

## The runner

`check` proves anchors *bind* to real goals; the **runner** proves each anchor is
*executable*. pharnoss does not force a runner, but ships a reference one: `pharnoss run`
reads each anchor's `status` and runs its check command (`cmd`, else `[runner].anchor_cmd`
with `{name}` substituted), applying:

| status  | check fails        | check passes                        |
|---------|--------------------|-------------------------------------|
| pending | expected → green   | READY TO PROMOTE → red (freeze it)  |
| frozen  | REGRESSION → red   | ok → green                          |

Exit `0` green / `1` red / `2` setup. Promotion = flip `status` pending→frozen (one field;
the test does not move). A project with its own contract harness points `[runner]` at it and
ignores `pharnoss run`. `pharnoss init --example` scaffolds a working end-to-end sample (one
goal, one differential anchor, a tiny impl) where both `check` and `run` are green.

## Status

Standalone, installable from GitHub, with a CLI and project scaffolding. Dogfooded on a
real Rust project and a non-Rust toy project (markdown goals / Python runner). Next:
publish to an index; a richer `init` (detect the project's runner); per-project
skill-install via `pharnoss init`.
