Skip to content

HTTP API: pack

The tracked tree as a few token-bounded Markdown shards a language model's file search can index, with an index that orients the reader and a manifest that proves afterwards what left the machine: the git index's blobs only, never the working tree, and never a binary, a gitlink or worktree, a symbolic link, build output or a credential, whatever the index holds.

Rendered from docs/generated/openapi.json, which the executable generates from its capability registry and CI refuses stale. The raw document is at /openapi.json; a running server serves the same document at its own /openapi.json and Swagger UI at /swagger.

pack

The tracked tree as a few token-bounded Markdown shards a language model's file search can index, with an index that orients the reader and a manifest that proves afterwards what left the machine: the git index's blobs only, never the working tree, and never a binary, a gitlink or worktree, a symbolic link, build output or a credential, whatever the index holds.

GET /api/v1/pack/plan pack.plan

Plan a source pack

What a profile of share/archive.yaml would pack: the files carried and their bytes and o200k_base tokens, every file left out by reason (worktree, link, artifact, binary, derived, excluded; derived counted, the rest listed), the shards it is cut into within the profile's token budget and file count, and every finding that refuses the build — a file over the budget, too many shards, a machine path or credential in a selected file, an empty selection, a profile without limits. Reads git's index and blobs only; writes nothing.

  • query
  • behaviorally_verified
  • benchmark required
  • cache disabled
  • MCP tool majordomus_pack_plan
  • $ pack plan

Query parameters

nametyperequireddescriptionexamples
profile string no A profile of `share/archive.yaml`; its `default` when absent. chatgpt: "chatgpt"

Try it

The port is whatever the server logged; 8741 is the one it asks for first. The values are the operation's first example.

curl -s "http://127.0.0.1:8741/api/v1/pack/plan?profile=chatgpt"

Tested by apps/majordomus-cli/tests/http_serve.rs, which replays the route with these values against a server on a real socket.

Responses

statusbodymeaning
200 PackPlan Plan a source pack: the result.
400 ErrorBody invalid_input: The input does not fit the schema: a parameter of the wrong type, an unknown one, or a value the capability rejects.
404 ErrorBody not_found: The input names something the repository does not hold.
500 ErrorBody internal: The capability failed for a reason of its own; the message names it.
default ErrorBody Any other failure the transport reports: 405 method_not_allowed for another method on this path, 400 invalid_input for a body that is not a JSON object.
GET /api/v1/pack/verify pack.verify

Verify a written source pack

Read a pack directory inside the repository against its pack.json: every file it names is present with its digest and nothing else is, every carried file's content has the digest its marker records, no carried path is a binary, an artifact, a link or a gitlink under the profile the manifest names, no file is over the profile's token budget or holds a NUL byte or a leak, and there are no more files than the profile allows. An unreadable manifest is unmeasured, never a pass.

  • query
  • behaviorally_verified
  • benchmark required
  • cache disabled
  • MCP tool majordomus_pack_verify
  • $ pack verify

Query parameters

nametyperequireddescriptionexamples
dir string yes The pack's directory, inside the repository: relative to its root, or absolute under it. absent: "tmp/packs/absent"

Try it

The port is whatever the server logged; 8741 is the one it asks for first. The values are the operation's first example.

curl -s "http://127.0.0.1:8741/api/v1/pack/verify?dir=tmp%2Fpacks%2Fabsent"

Tested by apps/majordomus-cli/tests/http_serve.rs, which replays the route with these values against a server on a real socket.

Responses

statusbodymeaning
200 PackVerdict Verify a written source pack: the result.
400 ErrorBody invalid_input: The input does not fit the schema: a parameter of the wrong type, an unknown one, or a value the capability rejects.
404 ErrorBody not_found: The input names something the repository does not hold.
500 ErrorBody internal: The capability failed for a reason of its own; the message names it.
default ErrorBody Any other failure the transport reports: 405 method_not_allowed for another method on this path, 400 invalid_input for a body that is not a JSON object.

Schemas

The components only this tag's operations use. Each row is the type's own field, its doc comment the description; a type another page owns links there.

DropReason

"worktree" | "link" | "artifact" | "binary" | "derived" | "excluded"
Why a tracked file is not in the pack. Every reason but derived and excluded is final: no include of a profile re-admits a link, a gitlink, an artifact or a binary.

use majordomus_cli::pack::DropReason;
assert_eq!(DropReason::Binary.as_str(), "binary");
let json = serde_json::to_string(&DropReason::Artifact).unwrap();
assert_eq!(json, "\"artifact\"");
  • worktreeA gitlink: a nested repository or worktree whose content is not in this index.
  • linkA symbolic link, whose content is a path on the machine that committed it.
  • artifactA path the distribution names as build output, a cache or a worktree container.
  • binaryNot text: a NUL byte, content that is not UTF-8, or an extension on the binary list.
  • derivedMarked merge=derived in .gitattributes: a projection of a file that is here.
  • excludedMatched by the profile's exclude.

Used by DroppedFile

DroppedFile

object
One dropped file the report names. Derived files are counted, not listed: they are a function of files that are in the pack.

The examples below plan a repository holding main.rs and a logo.png whose content is binary, with a distribution whose chat profile has limits and whose bare one has none.

use majordomus_cli::pack::{plan, DropReason, DroppedFile};
#### use std::process::Command;
#### let dir = tempfile::tempdir().unwrap();
#### let (root, share) = (dir.path().join("repo"), dir.path().join("share"));
#### std::fs::create_dir_all(&root).unwrap();
#### std::fs::create_dir_all(&share).unwrap();
#### std::fs::write(share.join("archive.yaml"), "default: chat\nprofiles:\n  - id: chat\n    binary: drop\n    artifacts: drop\n    shards:\n      max_count: 5\n      max_tokens: 4000\n  - id: bare\n    binary: drop\n").unwrap();
#### let git = |a: &[&str]| assert!(Command::new("git").arg("-C").arg(&root)
####     .args(["-c", "user.email=t@example.com", "-c", "user.name=t"]).args(a)
####     .status().unwrap().success());
#### git(&["init", "-q"]);
#### std::fs::write(root.join("main.rs"), "fn main() {}\n").unwrap();
#### std::fs::write(root.join("logo.png"), b"\x89PNG\0\x01").unwrap();
#### git(&["add", "-A"]);
#### git(&["commit", "-q", "-m", "one"]);
let dropped = plan(&root, &share, None).plan.dropped_files;
let want = DroppedFile { path: "logo.png".into(), reason: DropReason::Binary };
assert_eq!(dropped, [want]);
propertytyperequireddescription
path string yes The path.
reason DropReason → DropReason yes Why.

Used by PackPlan

PackFinding

object
A reason the pack cannot be built as planned, or a written pack is not what its manifest says: a stable code, the path when there is one, and the remedy.

The examples below plan a repository holding main.rs and a logo.png whose content is binary, with a distribution whose chat profile has limits and whose bare one has none.

use majordomus_cli::pack::{plan, PackFinding};
#### use std::process::Command;
#### let dir = tempfile::tempdir().unwrap();
#### let (root, share) = (dir.path().join("repo"), dir.path().join("share"));
#### std::fs::create_dir_all(&root).unwrap();
#### std::fs::create_dir_all(&share).unwrap();
#### std::fs::write(share.join("archive.yaml"), "default: chat\nprofiles:\n  - id: chat\n    binary: drop\n    artifacts: drop\n    shards:\n      max_count: 5\n      max_tokens: 4000\n  - id: bare\n    binary: drop\n").unwrap();
#### let git = |a: &[&str]| assert!(Command::new("git").arg("-C").arg(&root)
####     .args(["-c", "user.email=t@example.com", "-c", "user.name=t"]).args(a)
####     .status().unwrap().success());
#### git(&["init", "-q"]);
#### std::fs::write(root.join("main.rs"), "fn main() {}\n").unwrap();
#### std::fs::write(root.join("logo.png"), b"\x89PNG\0\x01").unwrap();
#### git(&["add", "-A"]);
#### git(&["commit", "-q", "-m", "one"]);
let findings: Vec<PackFinding> = plan(&root, &share, Some("bare")).plan.findings;
assert_eq!(findings[0].code, "pack.no_limits");
assert!(findings[0].path.is_none() && !findings[0].remedy.is_empty());
propertytyperequireddescription
code string yes A stable code: pack.file_too_large, pack.too_many_shards, pack.index_too_large, pack.leak, pack.empty, pack.no_limits, and from verification pack.tampered, pack.not_text, pack.forbidden_path, pack.missing, pack.stray, pack.over_budget, pack.manifest.
path string | null no The path the finding is about, when it is about one.
message string yes What is wrong.
remedy string yes What settles it.

Used by PackPlan PackVerdict

PackPlan

object
The plan of one pack: what it carries, what it leaves out and why, how it is cut into shards, and whether it may be built.

The examples below plan a repository holding main.rs and a logo.png whose content is binary, with a distribution whose chat profile has limits and whose bare one has none.

use majordomus_cli::pack::{plan, PackPlan};
#### use std::process::Command;
#### let dir = tempfile::tempdir().unwrap();
#### let (root, share) = (dir.path().join("repo"), dir.path().join("share"));
#### std::fs::create_dir_all(&root).unwrap();
#### std::fs::create_dir_all(&share).unwrap();
#### std::fs::write(share.join("archive.yaml"), "default: chat\nprofiles:\n  - id: chat\n    binary: drop\n    artifacts: drop\n    shards:\n      max_count: 5\n      max_tokens: 4000\n  - id: bare\n    binary: drop\n").unwrap();
#### let git = |a: &[&str]| assert!(Command::new("git").arg("-C").arg(&root)
####     .args(["-c", "user.email=t@example.com", "-c", "user.name=t"]).args(a)
####     .status().unwrap().success());
#### git(&["init", "-q"]);
#### std::fs::write(root.join("main.rs"), "fn main() {}\n").unwrap();
#### std::fs::write(root.join("logo.png"), b"\x89PNG\0\x01").unwrap();
#### git(&["add", "-A"]);
#### git(&["commit", "-q", "-m", "one"]);
let p: PackPlan = plan(&root, &share, None).plan;
assert!(p.measured && p.passes && p.index_matches_head);
assert_eq!((p.tracked, p.selected), (2, 1));
assert_eq!(p.dropped["binary"], 1);
// an unknown profile is not measured, and not measured is never a pass
let p: PackPlan = plan(&root, &share, Some("nope")).plan;
assert!(!p.measured && !p.passes);
propertytyperequireddescription
measured boolean yes Whether the tree could be read at all. false is not a pass.
reason string | null no Why it could not, when it could not.
profile string yes The profile planned.
commit string | null no The commit HEAD names; the content is the index's, which equals it when index_matches_head is true.
index_matches_head boolean yes Whether the index holds exactly what HEAD holds. false means staged changes travel with the pack under a commit id that does not contain them.
tracked integer (uint) yes How many files the index tracks.
selected integer (uint) yes How many the pack carries.
bytes integer (uint64) yes The bytes of the content carried.
tokens integer (uint64) yes The tokens of the content carried, in o200k_base.
tokenizer string yes The tokenizer the counts are in.
limits ShardLimits | null → ShardLimits no The limits applied.
dropped map of integer (uint) yes How many files were left out, by reason.
dropped_files array of DroppedFile → DroppedFile yes Every file left out for a reason other than derived.
shards array of ShardPlan → ShardPlan yes The shards, in order; the index is not one of them.
findings array of PackFinding → PackFinding yes Every reason the pack cannot be built. Empty is the passing answer.
passes boolean yes true when the tree was measured and nothing was found.

Used by pack.plan

PackVerdict

object
The verdict on a written pack: whether it could be read, what its manifest names, how many files and sources it holds, and every finding against it.

The examples below build a pack of a repository holding main.rs.

use majordomus_cli::pack::{build, plan, verify, PackVerdict, Profiles};
#### use std::process::Command;
#### let dir = tempfile::tempdir().unwrap();
#### let (root, share) = (dir.path().join("repo"), dir.path().join("share"));
#### std::fs::create_dir_all(&root).unwrap();
#### std::fs::create_dir_all(&share).unwrap();
#### std::fs::write(share.join("archive.yaml"), "default: chat\nprofiles:\n  - id: chat\n    binary: drop\n    artifacts: drop\n    shards:\n      max_count: 5\n      max_tokens: 4000\n").unwrap();
#### let git = |a: &[&str]| assert!(Command::new("git").arg("-C").arg(&root)
####     .args(["-c", "user.email=t@example.com", "-c", "user.name=t"]).args(a)
####     .status().unwrap().success());
#### git(&["init", "-q"]);
#### std::fs::write(root.join("main.rs"), "fn main() {}\n").unwrap();
#### git(&["add", "-A"]);
#### git(&["commit", "-q", "-m", "one"]);
let profiles = Profiles::load(&share, &root).unwrap();
let out = dir.path().join("pack");
let v: PackVerdict = build(&plan(&root, &share, None), &root, &out).unwrap();
assert_eq!((v.files, v.sources), (2, 1), "the index and one shard, carrying one file");
assert_eq!(v.profile.as_deref(), Some("chat"));
// a directory with no manifest is not measured, which is not a pass
let v: PackVerdict = verify(dir.path(), &profiles, &root);
assert!(!v.measured && !v.passes);
propertytyperequireddescription
measured boolean yes Whether the pack could be read at all. false is not a pass.
reason string | null no Why it could not, when it could not.
dir string yes The directory read.
profile string | null no The profile its manifest names.
commit string | null no The commit its manifest names.
files integer (uint) yes How many files it holds, the index included.
sources integer (uint) yes How many source files its shards carry.
largest_tokens integer (uint64) yes The tokens of its largest file.
findings array of PackFinding → PackFinding yes Every finding. Empty is the passing answer.
passes boolean yes true when the pack was read and nothing was found.

Used by pack.verify

ShardLimits

object
The shard limits of a profile: the reader's own limits on what it can index, the file count of a project and the tokens one file of it may hold.

use majordomus_cli::pack::{Profiles, ShardLimits};
let p = Profiles::parse(
    "default: a\nprofiles:\n  - id: a\n    shards:\n      max_count: 20\n      max_tokens: 900\n",
)
.unwrap();
let want = ShardLimits { max_count: 20, max_tokens: 900 };
assert_eq!(p.profile(None).unwrap().shards, Some(want));
propertytyperequireddescription
max_count integer (uint) yes The most files the pack may hold, the index included.
max_tokens integer (uint64) yes The most tokens one file of the pack may hold, counted with o200k_base.

Used by PackPlan

ShardPlan

object
One planned shard: a Markdown file of the pack, the paths it carries from first to last, and what it weighs in bytes and in tokens.

The examples below plan a repository holding main.rs and a logo.png whose content is binary, with a distribution whose chat profile has limits and whose bare one has none.

use majordomus_cli::pack::{plan, ShardPlan};
#### use std::process::Command;
#### let dir = tempfile::tempdir().unwrap();
#### let (root, share) = (dir.path().join("repo"), dir.path().join("share"));
#### std::fs::create_dir_all(&root).unwrap();
#### std::fs::create_dir_all(&share).unwrap();
#### std::fs::write(share.join("archive.yaml"), "default: chat\nprofiles:\n  - id: chat\n    binary: drop\n    artifacts: drop\n    shards:\n      max_count: 5\n      max_tokens: 4000\n  - id: bare\n    binary: drop\n").unwrap();
#### let git = |a: &[&str]| assert!(Command::new("git").arg("-C").arg(&root)
####     .args(["-c", "user.email=t@example.com", "-c", "user.name=t"]).args(a)
####     .status().unwrap().success());
#### git(&["init", "-q"]);
#### std::fs::write(root.join("main.rs"), "fn main() {}\n").unwrap();
#### std::fs::write(root.join("logo.png"), b"\x89PNG\0\x01").unwrap();
#### git(&["add", "-A"]);
#### git(&["commit", "-q", "-m", "one"]);
let planned = plan(&root, &share, None);
let first: &ShardPlan = &planned.plan.shards[0];
assert_eq!((first.files, first.first.as_str(), first.last.as_str()), (1, "main.rs", "main.rs"));
assert!(first.file.ends_with(".md") && first.tokens > 0);
propertytyperequireddescription
file string yes The file name inside the pack.
files integer (uint) yes How many files it carries.
first string yes The first path it carries.
last string yes The last path it carries.
bytes integer (uint64) yes The bytes of the content it carries.
tokens integer (uint64) yes The tokens of the blocks it carries.

Used by PackPlan

Searches the titles and descriptions of every page this site publishes.