Skip to main content

Ahead-of-time compiler/linker for LLM agent prompts — compose instruction sets from interchangeable parts.

Project description

prompt-linker

PyPI Downloads Python License: MIT

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

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

A configurable agent has variable behavior threaded through a stable algorithm. Two usual ways to manage that both rot:

  • inline conditionals (if mode == X …) entangle every variation into one monolith — and the branching is scattered through the prose, so you can no longer see at a glance where a scenario forks, which branch is live, or test one branch in isolation;
  • runtime resolution scatters the same behavior across tool-calls resolved on every iteration.

prompt-linker makes each variable behavior an interchangeable implementation behind a contract, so the skeleton never knows which one it got (substitutability — "Liskov for prompts" as a design metaphor: the linker proves the structure deterministically — every slot bound exactly once to an existing impl of the right contract — while semantic fit of the text is reviewed by the opt-in AI verifier, not proven; prose has no scope isolation, so that honesty is by design). Branching stops being buried in the text and becomes explicit data in the manifest — one line per binding, so where a scenario forks and which branch is active is readable in one place. The payoff is readable, independently-testable building blocks and Open–Closed growth: a new behavior is a new implementation + a manifest line, the algorithm is never edited. As a side effect the indirection is paid once, in deterministic code (zero model tokens) — the bonus, not the reason.

What you get beyond templating

A template engine gets you variable substitution. The value of prompt-linker is everything wrapped around that step:

  • A verifier that fails closed. Before a byte is written, every slot must resolve to exactly one existing implementation of the right contract; a missing, ambiguous, or duplicate binding is a typed error, never a silent default. A linker without a verifier is a generator of silently-incoherent prompts — here they ship as a pair, plus an opt-in AI verifier (check) for conformance and whole-artifact coherence.
  • Deploy as a first-class consumption mode. deploy lays a build out into host paths and records a committed deploy-receipt.json (config hash + per-file sha256); it refuses to overwrite hand-edited or foreign files, prunes what a rebuild dropped, and deploy --check is a CI/pre-commit gate that catches stale or hand-edited artifacts. Distribution is reproducible and auditable, not a copy script.
  • Reproducibility by construction. Output is content-addressed (compiled/<name>-<config-hash>), so a host can freeze a run to the exact artifact it started with — a manifest edit can never mutate the bytes an in-flight run reads.
  • A security layer for the prompt supply chain. A deterministic scan runs inside every verify/compile (invisible/bidi characters hard-fail; capability-envelope violations hard-fail; heuristics warn — and a contract that declares a capability allowed silences that noise), and opt-in chunk-hash pinning (approve → committed chunks.lock) turns any unreviewed corpus edit into a build failure.
  • Provenance everywhere. Every compiled file carries a GENERATED header with the full resolved binding and its hash; list --explain and diff show which layer won each binding and what it overrode.
  • CI-ready surface. Every command but init takes --json and emits one machine-readable result object — advisories, hashes, and output paths included.

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
Patch a small named set of contract → impl bindings — typically one axis of variation (a platform, a verbosity level)
Preset a named, ordered composition of patches (applied left→right, later wins); a point in the configuration space
Manifest Linker.yaml: names the configuration, declares patches: + presets: (+ global overrides:)
Binding / Resolution a contract → impl pair / the resolved set of them (defaults → preset (patches) → overrides)
Linker deterministic step that inlines implementations into skeletons
Verifier proves every slot is bound once and each implementation satisfies its contract

Quick look

# Linker.yaml
preset: team
overrides: { continuation: spawn-next }   # run-local contracts only
patches:                                  # small named binding sets — one per axis of variation
  base:    { task-source: local, continuation: stop }
  network: { task-source: tracker }
presets:                                  # a preset is an ordered list of patches (later wins)
  solo: [base]
  team: [base, network]                   # start from base, then apply the network axis
# 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 to begin your own configuration, or read Examples/TestConfiguration for a fuller, runnable one.

Install & adopt

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

pipx install prompt-linker            # or: uvx prompt-linker …
prompt-linker init prompts/my-config  # adopt the tool in the current repo

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. From a source checkout the entry point is PYTHONPATH=src python -m prompt_linker.

init is the one-shot, idempotent way for a host repo to adopt the tool. Run from the repo root, it:

  1. scaffolds a starter configuration into DIR (default prompts/my-config), with the manifest name: set to the dir basename and linker_version: stamped to the installed version;
  2. installs a Claude Code consumer skill into .claude/skills/prompt-linker/ that teaches a host agent to consume the tool (no internals);
  3. seeds configs.md next to the skill — a consumer-owned registry of this repo's configurations — and appends a row per scaffolded config;
  4. appends compiled/ to your .gitignore.

A non-empty DIR fails closed unless --force; pass --no-skill to scaffold only, or --skill-only to (re)install just the skill.

Upgrading / re-installing

The consumer skill ships inside the package, so a newer prompt-linker carries a newer skill — upgrade the package, then refresh the installed skill:

pipx upgrade prompt-linker             # or reinstall outright: pipx install --force prompt-linker
prompt-linker init --skill-only        # re-install just the skill from the new package

The skill is version-stamped managed (x-prompt-linker: {version, sha} in its front-matter): init overwrites a matching-or-absent skill silently — including on upgrade — but refuses a hand-edited one without --force, so customize by editing the source and re-init, never the installed copy. Your configs.md is never overwritten, so the repo's config list survives every upgrade. Find the version to pin a build against with prompt-linker --version (also stamped in the skill's x-prompt-linker.version).

Usage

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

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 §3.4).

Editor validation. The package ships a JSON Schema for Linker.yaml; one # yaml-language-server: $schema=… comment (scaffolds and Examples carry it already) gives any yaml-language-server editor autocomplete, hover docs, and typo flagging for the manifest while you type — see Docs/Commands.md.

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.

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): 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 — v2.2.0 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). 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, the CLI in Docs/Commands.md, verification layers in Docs/Verification.md, emitted errors in Docs/Errors.md; open questions and planned work in 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

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

prompt_linker-2.2.0.tar.gz (151.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

prompt_linker-2.2.0-py3-none-any.whl (85.6 kB view details)

Uploaded Python 3

File details

Details for the file prompt_linker-2.2.0.tar.gz.

File metadata

  • Download URL: prompt_linker-2.2.0.tar.gz
  • Upload date:
  • Size: 151.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.10

File hashes

Hashes for prompt_linker-2.2.0.tar.gz
Algorithm Hash digest
SHA256 059882842c6f908becd016272271c492b7dcb4a3594d3ca87ee3324d70540a8d
MD5 7277fcaf2833ac33fb472999272d0fca
BLAKE2b-256 c8cf16e685b0da3db63671892497efe7870af38e0d2cd6936527a1fc24df33cc

See more details on using hashes here.

File details

Details for the file prompt_linker-2.2.0-py3-none-any.whl.

File metadata

  • Download URL: prompt_linker-2.2.0-py3-none-any.whl
  • Upload date:
  • Size: 85.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.10

File hashes

Hashes for prompt_linker-2.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 62edfe92d2c47a197d1427663b9fef6ed7bcef3b7369dba614ae5e3e010fc435
MD5 04eb82783633cf5bc2e9a36fc15a5d4d
BLAKE2b-256 a30ca8a4ed84f5b4642ccb1c3a67ca16119b5d61fdb430dbff23aa8af81dbd12

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page