Metadata-Version: 2.4
Name: prompt-linker
Version: 1.1.1
Summary: Ahead-of-time compiler/linker for LLM agent prompts — compose instruction sets from interchangeable parts.
Project-URL: Homepage, https://github.com/ega-ega/prompt-linker
Project-URL: Source, https://github.com/ega-ega/prompt-linker
Author: Egor Shaldov
License-Expression: MIT
License-File: LICENSE
Keywords: agent,compiler,linker,llm,pipeline,prompt
Requires-Python: >=3.11
Requires-Dist: pyyaml>=6.0
Provides-Extra: ai
Requires-Dist: anthropic<1,>=0.69; extra == 'ai'
Provides-Extra: dev
Requires-Dist: mypy>=1.10; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: ruff>=0.5; extra == 'dev'
Description-Content-Type: text/markdown

# prompt-linker

[![PyPI](https://img.shields.io/pypi/v/prompt-linker.svg)](https://pypi.org/project/prompt-linker/)
[![Downloads](https://img.shields.io/pypi/dm/prompt-linker.svg)](https://pypi.org/project/prompt-linker/)
[![Python](https://img.shields.io/pypi/pyversions/prompt-linker.svg)](https://pypi.org/project/prompt-linker/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)

> Compile an LLM agent's instruction set from interchangeable parts — the way a program is
> linked from objects chosen at build time.

**prompt-linker** is an ahead-of-time **compiler/linker for agent prompts**. You write a stable
algorithm as *skeletons with named slots*, write the variable behavior as *interchangeable
implementations*, and declare which implementation fills each slot in a *build manifest*. The linker
inlines the chosen implementations into the skeletons and emits one flat, fully-resolved instruction
that the agent runs with **zero runtime indirection**.

## Why

Configurable agent pipelines usually rot in one of two ways:

- **inline conditionals** (`if mode == X …`) entangle every variation into one monolith;
- **runtime resolution** pays a tool-call + tokens for every slot, on every iteration.

prompt-linker pays its indirection **once, in deterministic code (zero model tokens)**, and hands the
agent a single readable artifact. "Modes" become *data* — named presets over a small space of
bindings — not branches in the engine. Adding a new behavior is **a new implementation + a manifest
line**; the algorithm is never edited (Open–Closed).

## Concepts

| Term | Is |
|---|---|
| **Configuration** | a self-contained directory (manifest + `skeletons/` + `contracts/`) that compiles independently; a project may hold many |
| **Contract** | a named, reusable signature (inputs, postcondition, invariant); declared once, with an optional default impl |
| **Slot** | an occurrence of a contract in a skeleton — `{{ slot: <contract-id> }}`, the hole to fill |
| **Implementation** | one concrete block that satisfies a contract and fills its slots |
| **Skeleton** | a prompt template containing slots |
| **Skill** | a deliverable bundle (a top-level subdir of `skeletons/`) — a convention, not required |
| **Manifest** | `Linker.yaml`: names the configuration, binds each contract → an impl (+ named presets) |
| **Binding / Resolution** | a `contract → impl` pair / the resolved set of them (`defaults → preset → overrides`) |
| **Linker** | deterministic step that inlines implementations into skeletons |
| **Verifier** | proves every slot is bound once and each implementation satisfies its contract |

## Quick look

```yaml
# Linker.yaml
preset: team
overrides: { continuation: spawn-next }   # run-local contracts only
presets:
  solo: { task-source: local,   continuation: stop }
  team: { extends: solo, task-source: tracker }
```

```markdown
# skeletons/autonomous-agent/run.md
## Phase 1 — Acquire work
{{ slot: task-source }}
```

`prompt-linker compile --preset team` → a flat `compiled/<name>-<config-hash>/autonomous-agent/run.md`
with the `tracker` implementation inlined — clean text the agent reads with no hint it was assembled
from parts (the output dir is content-addressed so a host can freeze a run by recording its path);
provenance lives in a `GENERATED` header. (`compile --annotated` adds per-block markers for an AI
verifier — a debug build, never shipped.) Copy [`Examples/StarterTemplate`](./Examples/StarterTemplate)
to begin your own configuration, or read [`Examples/TestConfiguration`](./Examples/TestConfiguration)
for a fuller, runnable one.

## Install & adopt

prompt-linker is on PyPI — consume it as an **installed package**, not a vendored copy:

```sh
pipx install prompt-linker            # or: uvx prompt-linker …
prompt-linker init prompts/my-config  # scaffold a configuration + install a consumer skill + patch .gitignore
```

**Use `pipx` or `uvx`** — they put the `prompt-linker` command on your `PATH` (and `uvx` runs it
without installing at all). Plain `pip install prompt-linker` also works, but then *you* manage
`PATH`: pip drops the command in a `Scripts/`/`bin` dir that is not always on it (notably with Windows
Store Python). If the bare command isn't found, run it PATH-independently with **`python -m
prompt_linker …`** — that always works wherever `python` does.

`init` is the one-shot way for a host repo to adopt the tool: it scaffolds a starter configuration,
appends `compiled/` to your `.gitignore`, and installs a small **Claude Code skill** into
`.claude/skills/prompt-linker/` that teaches a host agent to *consume* the tool (no internals). Use
`--skill-only` to refresh just the skill after an upgrade. From a source checkout the entry point is
`PYTHONPATH=src python -m prompt_linker`.

## Usage

Run a command against a configuration directory (its ROOT):

```sh
prompt-linker verify  Examples/TestConfiguration                  # check coherence; writes nothing
prompt-linker compile Examples/TestConfiguration --preset team    # → compiled/ (gitignored)
prompt-linker deploy  Examples/DeployExample  --root .            # install/distribute a build into host paths
prompt-linker check   Examples/TestConfiguration --security       # AI verifier (opt-in; needs [ai] extra)
prompt-linker approve Examples/TestConfiguration                  # pin the corpus → chunks.lock (review gate)
```

Two ways to consume a build: **use-in-place** (`compile`, then point the runtime agent at the printed
content-addressed path — commit nothing) or **install/distribute** (`deploy` — lay the build out into
host paths another tool discovers by location, recorded in a committed `deploy-receipt.json`;
`deploy --check` is the CI/pre-commit freshness gate).

`verify`, `compile`, and `deploy` are deterministic and fail closed (and include a security scan);
`check` is the opt-in, model-using AI verifier (conformance, coherence, injection review).

**Security — chunk-hash pinning (opt-in).** `prompt-linker approve` records the sha256 of every source
chunk (`contracts/` + `skeletons/`) into a committed `chunks.lock`; `verify`/`compile` then fail closed
on any drift until you review the change and re-`approve`. It is a tripwire, not a detector — its value
is realized by a review gate (e.g. CODEOWNERS on `contracts/**`, `skeletons/**`, `chunks.lock`) so a
corpus edit cannot land unreviewed ([`Docs/Verification.md`](./Docs/Verification.md) §3.4).

**CI / scripting.** Every command but `init` takes `--json` for one machine-readable result object on
stdout; `compile --json` exposes `out_dir`/`config_hash` as the hook a launch wrapper uses to *freeze* a
run to its content-addressed build. **Full command reference: [`Docs/Commands.md`](./Docs/Commands.md).**

## Versioning & reproducibility

prompt-linker is consumed as an installed package, never vendored — so the **only** lever for a
reproducible build is **pinning the version exactly** (`prompt-linker==X.Y.Z`). A compiler's output can
shift across versions (slot handling, the `GENERATED` header, advisories), so identical sources can build
differently under a different tool. The bump level signals *intent* (see the
[versioning policy](./CHANGELOG.md#versioning-policy)): MAJOR = breaking surface/format/output, MINOR =
backward-compatible additions (and output-correcting fixes), PATCH = no intended output/surface change.
Only an exact pin guarantees byte-identical output.

- Find the version to pin: `prompt-linker --version` (also stamped in the installed skill's
  `x-prompt-linker.version`).
- Make drift loud: record `linker_version: X.Y.Z` in a config's `Linker.yaml` (`init` stamps it) and
  `verify` warns when the installed CLI differs.

## Status

✅ **Stable — v1.1.1 on PyPI** (`prompt-linker`; the badge above shows the current version). Since
1.0.0 the CLI surface, the emitted formats, and the `Linker.yaml` schema are under SemVer (see the
[versioning policy](./CHANGELOG.md#versioning-policy)). The
deterministic linker/verifier, the opt-in AI verifier, host adoption (`init`), and both consumption
modes (`compile` / `deploy`) all run; `--json` machine-readable output and opt-in chunk-hash pinning
(`approve`) round out the surface. Docs: the design in [`Docs/PromptLinker.md`](./Docs/PromptLinker.md), the CLI in
[`Docs/Commands.md`](./Docs/Commands.md), verification layers in
[`Docs/Verification.md`](./Docs/Verification.md), emitted errors in [`Docs/Errors.md`](./Docs/Errors.md);
open questions and planned work in [`Roadmap/Roadmap.md`](./Roadmap/Roadmap.md).

**Implementation:** Python 3.11+, distributed via PyPI (`pipx run prompt-linker` / `uvx
prompt-linker`). The npm name is reserved; a native JS build is deferred until there is demand for
embedding the linker as a JS library.

## License

[MIT](./LICENSE)
