@byollm/protocol 0.1.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/audience.ts","../src/backends.ts","../src/kinds.ts","../src/job.ts","../src/musts.ts","../src/wire.ts"],"sourcesContent":["import { z } from \"zod\";\nimport { type BackendAccount } from \"./backends.js\";\n\n/**\n * Who may run a job, declared by the app that enqueued it.\n *\n * - `self` — only the job owner's own daemon.\n * - `named` — a daemon whose owner has explicitly allowed this (server, user)\n * pair in their *local* allowlist (byollm_001 Rev 1 §B).\n * - `public` — any daemon offering `public` compute.\n */\nexport const Audience = z.enum([\"self\", \"named\", \"public\"]);\nexport type Audience = z.infer<typeof Audience>;\n\n/**\n * What a daemon backend is willing to run, declared by the machine's owner.\n * Same three values as {@link Audience}, but the two are independent axes —\n * a job runs only where both agree ({@link MUSTS.AUDIENCE_BOTH_SIDES}).\n */\nexport const OfferScope = z.enum([\"self\", \"named\", \"public\"]);\nexport type OfferScope = z.infer<typeof OfferScope>;\n\n/** All audience values, in widening order. */\nexport const AUDIENCES = Object.freeze(Audience.options);\n/** All offer scopes, in widening order. */\nexport const OFFER_SCOPES = Object.freeze(OfferScope.options);\n\n/**\n * Why a job was refused. Distinct codes because byollm_002 requires that\n * different truths never share a message — \"no matching work\" and \"refused on\n * principle\" are not the same event, and a volunteer debugging their setup\n * needs to know which one happened.\n */\nexport const MatchRefusal = z.enum([\n /** The daemon advertises no capability for this kind. */\n \"no-capability\",\n /** Job is `self` but this daemon belongs to a different user. */\n \"audience-self-other-owner\",\n /** Job is `named` but this daemon's local allowlist does not admit the owner. */\n \"not-locally-allowed\",\n /** Job is `named`/`public` but the server's own allowlist excludes this runner. */\n \"not-in-server-allowlist\",\n /** The backend offers only `self` and the job belongs to someone else. */\n \"offer-scope-too-narrow\",\n /** The matched backend is subscription-class, which is locked to `self`. */\n \"subscription-self-lock\",\n]);\nexport type MatchRefusal = z.infer<typeof MatchRefusal>;\n\n/** The outcome of an audience match. */\nexport type MatchResult =\n | { readonly ok: true }\n | { readonly ok: false; readonly refusal: MatchRefusal };\n\nconst ALLOWED: MatchResult = Object.freeze({ ok: true as const });\nconst refuse = (refusal: MatchRefusal): MatchResult =>\n Object.freeze({ ok: false as const, refusal });\n\n/**\n * The effective offer scope of a backend.\n *\n * A subscription-class backend is locked to `self` regardless of what config\n * requests ({@link MUSTS.SUBSCRIPTION_SELF_LOCK}). This is a protocol MUST,\n * not a setting: the lock is applied here, at the one place both the daemon's\n * config loader and its matcher call, so there is no code path that observes\n * a widened subscription scope.\n */\nexport function effectiveOfferScope(\n configured: OfferScope,\n account: BackendAccount,\n): OfferScope {\n return account === \"subscription\" ? \"self\" : configured;\n}\n\n/** The job-side facts a match needs. */\nexport interface MatchJob {\n /** The app's id for the user who enqueued the job. */\n readonly owner: string;\n /** Who the app says may run it. */\n readonly audience: Audience;\n /**\n * Optional server-side restriction on which runner owners may take a\n * `named` job. Defence in depth only — the daemon's local allowlist is the\n * enforcing side ({@link MUSTS.NAMED_LOCAL_ALLOWLIST}).\n */\n readonly audienceAllow?: readonly string[] | undefined;\n}\n\n/** The daemon-side facts a match needs. */\nexport interface MatchDaemon {\n /** The app's id for the user this daemon is paired to. */\n readonly owner: string;\n /** Effective scope of the backend that would run the job. */\n readonly offerScope: OfferScope;\n /** Account class of that backend. */\n readonly account: BackendAccount;\n /**\n * Does this daemon's *local* allowlist admit the given owner for the server\n * origin the job came from? Supplied as a predicate so the protocol package\n * stays free of file I/O; the daemon passes its allowlist, the server\n * passes a conservative `() => true` because it cannot know a remote\n * daemon's local list and must not pretend to.\n */\n readonly locallyAllows: (owner: string) => boolean;\n}\n\n/**\n * Decide whether a job may run on a daemon.\n *\n * Both sides must agree ({@link MUSTS.AUDIENCE_BOTH_SIDES}):\n * 1. the job's audience must admit the daemon's owner, and\n * 2. the backend's offer scope must admit the job's owner.\n *\n * The full nine-way matrix (three audiences × three offer scopes) is asserted\n * by the conformance kit. The function is pure and total so both the daemon\n * and the server can run the identical rule — the daemon refuses, and the\n * server refuses too (byollm_003 §Server-side MUSTs).\n *\n * @example\n * ```ts\n * const result = matchAudience(\n * { owner: \"alice\", audience: \"named\" },\n * {\n * owner: \"bob\",\n * offerScope: \"named\",\n * account: \"open\",\n * locallyAllows: (o) => o === \"alice\",\n * },\n * );\n * // result.ok === true\n * ```\n */\nexport function matchAudience(job: MatchJob, daemon: MatchDaemon): MatchResult {\n const sameOwner = job.owner === daemon.owner;\n\n // --- Side 1: does the job's audience admit this daemon's owner? --------\n if (job.audience === \"self\" && !sameOwner) {\n return refuse(\"audience-self-other-owner\");\n }\n if (\n job.audience === \"named\" &&\n !sameOwner &&\n job.audienceAllow !== undefined &&\n !job.audienceAllow.includes(daemon.owner)\n ) {\n return refuse(\"not-in-server-allowlist\");\n }\n\n // --- Side 2: does the backend's offer scope admit the job's owner? -----\n // The lock is re-applied rather than trusted: a caller that passed a\n // widened scope for a subscription backend gets a refusal, not obedience.\n const scope = effectiveOfferScope(daemon.offerScope, daemon.account);\n\n if (sameOwner) {\n // A daemon always runs its own owner's work, at any scope.\n return ALLOWED;\n }\n\n if (daemon.account === \"subscription\") {\n return refuse(\"subscription-self-lock\");\n }\n\n switch (scope) {\n case \"self\":\n return refuse(\"offer-scope-too-narrow\");\n case \"named\":\n // byollm_001 Rev 1 §B: the daemon's own list decides, not the server's.\n return daemon.locallyAllows(job.owner)\n ? ALLOWED\n : refuse(\"not-locally-allowed\");\n case \"public\":\n return ALLOWED;\n }\n}\n\n/**\n * Human-readable refusal text for the daemon's log and the trust UI.\n * Each refusal reads as a distinct truth — byollm_002's \"four different\n * truths that must never share a message\" applied to the audience axis.\n */\nexport const REFUSAL_MESSAGES: Readonly<Record<MatchRefusal, string>> =\n Object.freeze({\n \"no-capability\":\n \"no backend on this machine is configured and healthy for that job kind\",\n \"audience-self-other-owner\":\n \"the job is private to its owner and this machine is paired to someone else\",\n \"not-locally-allowed\":\n \"the job's owner is not on this machine's allowlist (byollm allow <server> <user>)\",\n \"not-in-server-allowlist\":\n \"the app restricted this job to named runners and this machine is not one of them\",\n \"offer-scope-too-narrow\":\n \"this backend is offered to its owner only (byollm offer <backend> named|public to widen)\",\n \"subscription-self-lock\":\n \"subscription-backed models run their owner's work only — this is a protocol rule, not a setting\",\n });\n","import { z } from \"zod\";\n\n/**\n * How a backend reaches its model — the taxonomy introduced in byollm_001\n * Rev 1 §A, because the two classes have different threat surfaces.\n *\n * - `http`: an OpenAI-compatible HTTP server (Ollama, `mlx_lm.server`,\n * llama.cpp server, vLLM). Spawns nothing, so byollm_004 §2's argv, stdin,\n * env and sandbox requirements are not applicable by construction. Its\n * threat surface is SSRF-shaped and bounded by {@link MUSTS.HTTP_BASE_URL_SAFE}.\n * - `process`: spawns a binary (`claude` CLI today, `mlx_lm.lora` for a\n * future `train.*` kind). All of byollm_004 §2 is mandatory here.\n */\nexport const BackendClass = z.enum([\"http\", \"process\"]);\nexport type BackendClass = z.infer<typeof BackendClass>;\n\n/**\n * Whose account pays for the inference.\n *\n * `subscription` backends run against a vendor account belonging to the\n * machine's owner. They are hard-locked to an offer scope of `self`\n * ({@link MUSTS.SUBSCRIPTION_SELF_LOCK}) — one account executes one person's\n * work. This is orthogonal to {@link BackendClass}: `claude-cli` is both\n * process-class and subscription-class, while a future local `mlx_lm.lora`\n * backend would be process-class and open.\n */\nexport const BackendAccount = z.enum([\"open\", \"subscription\"]);\nexport type BackendAccount = z.infer<typeof BackendAccount>;\n\n/** The immutable facts about a backend that the protocol reasons over. */\nexport interface BackendDescriptor {\n /** Stable backend id, as written in `byollm.config.json`. */\n readonly id: string;\n /** Human-readable name for the trust UI. */\n readonly label: string;\n /** Determines which isolation requirements apply. */\n readonly class: BackendClass;\n /** Determines whether the offer scope can be widened past `self`. */\n readonly account: BackendAccount;\n /**\n * Which adversarial corpus byollm_004 §5 runs against this backend. A\n * backend cannot be registered without one — the coverage check in the\n * adversarial suite enforces it.\n */\n readonly adversarialCorpus: \"process\" | \"http\";\n}\n\nconst backend = (b: BackendDescriptor): BackendDescriptor => Object.freeze(b);\n\n/**\n * The v1 backend registry.\n *\n * byollm_001 Rev 1 §A collapses four planned backends into one HTTP-class\n * entry: Ollama, `mlx_lm.server`, llama.cpp server and vLLM all speak\n * OpenAI-compatible `/v1/chat/completions`, so they are one backend with N\n * owner-configured base URLs rather than four adapters. That is what puts\n * MLX inference in v1.\n */\nexport const BACKENDS = Object.freeze({\n \"openai-http\": backend({\n id: \"openai-http\",\n label: \"OpenAI-compatible HTTP server (Ollama, MLX, llama.cpp, vLLM)\",\n class: \"http\",\n account: \"open\",\n adversarialCorpus: \"http\",\n }),\n \"claude-cli\": backend({\n id: \"claude-cli\",\n label: \"Claude CLI (your subscription)\",\n class: \"process\",\n account: \"subscription\",\n adversarialCorpus: \"process\",\n }),\n} as const satisfies Record<string, BackendDescriptor>);\n\n/** The id of a registered backend. */\nexport type BackendId = keyof typeof BACKENDS;\n\n/** All registered backend ids — the adversarial coverage check iterates this. */\nexport const BACKEND_IDS = Object.freeze(Object.keys(BACKENDS) as BackendId[]);\n\nexport const BackendIdSchema = z.enum(\n BACKEND_IDS as [BackendId, ...BackendId[]],\n);\n\n/** Narrow an arbitrary string to a registered backend id. */\nexport function isBackendId(value: string): value is BackendId {\n return Object.hasOwn(BACKENDS, value);\n}\n\n/**\n * Look up a backend descriptor.\n *\n * @throws if the id is not registered — an unregistered backend has no\n * adversarial corpus, so refusing is the safe direction.\n */\nexport function backendDescriptor(id: BackendId): BackendDescriptor {\n return BACKENDS[id];\n}\n","import { z } from \"zod\";\n\n/**\n * Upper bounds on payload size, enforced at the schema so oversized input is\n * refused at parse time rather than somewhere deeper.\n *\n * byollm_004 §4 requires stricter limits for community (`named`/`public`)\n * jobs; those are applied on top of these by the daemon's budget check, which\n * knows the job's audience. These are the absolute ceilings for any job.\n */\nexport const PAYLOAD_LIMITS = Object.freeze({\n /** Max characters in any single text field. */\n maxTextChars: 1_000_000,\n /** Max messages in an `llm.chat` conversation. */\n maxMessages: 256,\n /** Max characters across the whole payload. */\n maxTotalChars: 4_000_000,\n});\n\n/**\n * A conversation turn. `role` is a closed enum — it is routing *within the\n * model call*, not routing of the call, so it cannot select a backend.\n */\nexport const ChatMessage = z.object({\n role: z.enum([\"system\", \"user\", \"assistant\"]),\n content: z.string().max(PAYLOAD_LIMITS.maxTextChars),\n});\nexport type ChatMessage = z.infer<typeof ChatMessage>;\n\n/**\n * Payload for `llm.generate`.\n *\n * @remarks\n * Text only, deliberately. byollm_004 §1 states the payload is \"data handed\n * to a model, never configuration and never a command\", so v0 carries no\n * sampling parameters, no model name, no base URL and no flags — those are\n * owner-side route config. A future `params` field with an explicit closed\n * allowlist and owner-set clamps is reserved; adding a field later is\n * non-breaking, removing one is not.\n */\nexport const GeneratePayload = z\n .object({\n prompt: z.string().min(1).max(PAYLOAD_LIMITS.maxTextChars),\n system: z.string().max(PAYLOAD_LIMITS.maxTextChars).optional(),\n })\n .strict();\nexport type GeneratePayload = z.infer<typeof GeneratePayload>;\n\n/** Payload for `llm.chat`. Text only, for the same reason as {@link GeneratePayload}. */\nexport const ChatPayload = z\n .object({\n messages: z.array(ChatMessage).min(1).max(PAYLOAD_LIMITS.maxMessages),\n system: z.string().max(PAYLOAD_LIMITS.maxTextChars).optional(),\n })\n .strict();\nexport type ChatPayload = z.infer<typeof ChatPayload>;\n\n/**\n * The job kinds a v1 daemon has handlers for.\n *\n * Kinds are resolved against handlers baked into the daemon\n * ({@link MUSTS.KIND_TYPED_ONLY}); an unknown kind is refused, never guessed.\n * Adding a kind is a protocol change with its own spec and threat review —\n * notably any kind that needs tools, which byollm_004 §2 forbids as a payload\n * flag.\n */\nexport const JobKind = z.enum([\"llm.generate\", \"llm.chat\"]);\nexport type JobKind = z.infer<typeof JobKind>;\n\n/** All v1 job kinds. */\nexport const JOB_KINDS = Object.freeze(JobKind.options);\n\n/** A payload discriminated by its kind. */\nexport const KindedPayload = z.discriminatedUnion(\"kind\", [\n z.object({ kind: z.literal(\"llm.generate\"), payload: GeneratePayload }),\n z.object({ kind: z.literal(\"llm.chat\"), payload: ChatPayload }),\n]);\nexport type KindedPayload = z.infer<typeof KindedPayload>;\n\n/** The payload type for a given kind. */\nexport type PayloadFor<K extends JobKind> = K extends \"llm.generate\"\n ? GeneratePayload\n : ChatPayload;\n\n/** Narrow an arbitrary string to a known job kind. */\nexport function isJobKind(value: string): value is JobKind {\n return (JOB_KINDS as readonly string[]).includes(value);\n}\n\n/**\n * Total character weight of a payload, used by the daemon's community budget\n * check and by the server's payload-size limits.\n */\nexport function payloadTextLength(kinded: KindedPayload): number {\n if (kinded.kind === \"llm.generate\") {\n return kinded.payload.prompt.length + (kinded.payload.system?.length ?? 0);\n }\n const messages = kinded.payload.messages.reduce(\n (sum, m) => sum + m.content.length,\n 0,\n );\n return messages + (kinded.payload.system?.length ?? 0);\n}\n","import { z } from \"zod\";\nimport { Audience } from \"./audience.js\";\nimport { BackendClass } from \"./backends.js\";\nimport { ChatPayload, GeneratePayload, JobKind } from \"./kinds.js\";\n\n/**\n * The job lifecycle, made explicit by byollm_001 Rev 1 §D because the most\n * user-visible failure mode — \"nothing is running my job\" — was previously\n * unspecified.\n *\n * ```text\n * queued ──claim──▶ claimed ──start──▶ running ──▶ ok | error | canceled\n * │ │ │\n * │ └──lease expiry─────┘\n * │ ▼\n * │ queued (reclaimable, no loss)\n * └──ttl elapsed──▶ expired\n * ```\n */\nexport const JobState = z.enum([\n \"queued\",\n \"claimed\",\n \"running\",\n \"ok\",\n \"error\",\n \"canceled\",\n \"expired\",\n]);\nexport type JobState = z.infer<typeof JobState>;\n\n/** States from which a job never moves again. */\nexport const TERMINAL_STATES = Object.freeze([\n \"ok\",\n \"error\",\n \"canceled\",\n \"expired\",\n] as const satisfies readonly JobState[]);\n\n/** Is this a state the job can never leave? */\nexport function isTerminal(state: JobState): boolean {\n return (TERMINAL_STATES as readonly JobState[]).includes(state);\n}\n\n/**\n * The legal transitions. Held as data so the store adapters and the\n * conformance kit agree on one definition rather than three implementations.\n */\nconst TRANSITIONS: Readonly<Record<JobState, readonly JobState[]>> =\n Object.freeze({\n queued: [\"claimed\", \"expired\", \"canceled\"],\n // A claimed job returns to `queued` when its lease expires un-renewed\n // ({@link MUSTS.LEASE_RECLAIMABLE}).\n claimed: [\"running\", \"queued\", \"canceled\", \"error\"],\n running: [\"ok\", \"error\", \"canceled\", \"queued\"],\n ok: [],\n error: [],\n canceled: [],\n expired: [],\n });\n\n/** May a job move from `from` to `to`? */\nexport function canTransition(from: JobState, to: JobState): boolean {\n return TRANSITIONS[from].includes(to);\n}\n\n/** A lease: the right to work on a job until `expiresAt`. */\nexport const Lease = z.object({\n /** The runner holding the lease. */\n runnerId: z.string().min(1),\n /** Epoch milliseconds after which the claim is void. */\n expiresAt: z.number().int().positive(),\n});\nexport type Lease = z.infer<typeof Lease>;\n\n/** Payload union as it appears on a job record. */\nexport const JobPayload = z.union([GeneratePayload, ChatPayload]);\nexport type JobPayload = z.infer<typeof JobPayload>;\n\n/**\n * A job as the daemon receives it from `/byollm/claim`.\n *\n * Note what is absent: no model, no backend, no base URL, no flags, no path.\n * Those come from the machine owner's config only\n * ({@link MUSTS.NO_PAYLOAD_ROUTING}). The wire shape is the first place that\n * rule is enforced — there is no field to carry them.\n */\nexport const ClaimedJob = z\n .object({\n id: z.string().min(1),\n kind: JobKind,\n payload: JobPayload,\n audience: Audience,\n /** The app's id for the user who enqueued it. */\n owner: z.string().min(1),\n /** Runner owners the app restricted a `named` job to, if any. */\n audienceAllow: z.array(z.string().min(1)).optional(),\n lease: Lease,\n })\n .strict();\nexport type ClaimedJob = z.infer<typeof ClaimedJob>;\n\n/**\n * The provenance that travels with every result to the delivery seam.\n *\n * byollm_003 Rev 1: a `named`/`public` result is attacker-controlled text.\n * The app must never render volunteer output as its own AI's answer without\n * knowing that is what it is ({@link MUSTS.RESULT_PROVENANCE}).\n */\nexport const ResultProvenance = z\n .object({\n /** The audience the job ran under. */\n audience: Audience,\n /** The runner that produced it. */\n runnerId: z.string().min(1),\n /** The runner owner's id in this app's namespace. */\n runnerOwner: z.string().min(1),\n /** Which backend class produced it — an HTTP call or a sandboxed spawn. */\n backendClass: BackendClass,\n /** The model the runner reports having used. */\n model: z.string().min(1),\n /**\n * False only for `self` jobs. When true the app MUST treat `text` as\n * untrusted third-party content.\n */\n untrusted: z.boolean(),\n })\n .strict();\nexport type ResultProvenance = z.infer<typeof ResultProvenance>;\n\n/**\n * Build provenance for a completed job. `untrusted` is derived, never\n * supplied, so no caller can mark volunteer output as first-party.\n */\nexport function provenanceFor(input: {\n audience: Audience;\n runnerId: string;\n runnerOwner: string;\n backendClass: BackendClass;\n model: string;\n}): ResultProvenance {\n return {\n audience: input.audience,\n runnerId: input.runnerId,\n runnerOwner: input.runnerOwner,\n backendClass: input.backendClass,\n model: input.model,\n untrusted: input.audience !== \"self\",\n };\n}\n\n/** Successful outcome. */\nexport const JobResultOk = z\n .object({\n outcome: z.literal(\"ok\"),\n text: z.string(),\n /** Optional reference to a stored artifact; never a local path. */\n artifactUrl: z.url().optional(),\n })\n .strict();\n\n/** Failed outcome. `code` is a stable machine string; `message` is for humans. */\nexport const JobResultError = z\n .object({\n outcome: z.literal(\"error\"),\n code: z.string().min(1),\n message: z.string().min(1),\n /** Whether the app may reasonably re-enqueue. */\n retryable: z.boolean(),\n })\n .strict();\n\n/** Cancelled outcome, reported by the daemon after honoring a cancel. */\nexport const JobResultCanceled = z\n .object({\n outcome: z.literal(\"canceled\"),\n })\n .strict();\n\nexport const JobOutcome = z.discriminatedUnion(\"outcome\", [\n JobResultOk,\n JobResultError,\n JobResultCanceled,\n]);\nexport type JobOutcome = z.infer<typeof JobOutcome>;\n\n/** A completed job as delivered to the app, provenance attached. */\nexport const DeliveredResult = z\n .object({\n jobId: z.string().min(1),\n state: JobState,\n outcome: JobOutcome.optional(),\n provenance: ResultProvenance.optional(),\n })\n .strict();\nexport type DeliveredResult = z.infer<typeof DeliveredResult>;\n","/**\n * The normative MUSTs of protocol v0, as data.\n *\n * byollm_001 requires that \"every MUST above has a conformance test id\n * referenced inline\". Keeping the MUSTs as a frozen registry rather than\n * prose is what makes that requirement *checkable*: the conformance kit\n * imports {@link MUSTS} and fails if any id has no test asserting it, so a\n * new MUST cannot be added without a test and a test cannot silently drift\n * away from the statement it claims to prove.\n *\n * Ids are stable and public — third-party servers cite them in their\n * certification output.\n */\n\n/** Which side of the wire is obliged to enforce a given MUST. */\nexport type MustEnforcer = \"daemon\" | \"server\" | \"both\";\n\n/** A single normative requirement of the protocol. */\nexport interface Must {\n /** Stable public id, cited by conformance output. */\n readonly id: string;\n /** The requirement, in MUST language. */\n readonly statement: string;\n /** Which implementation is obliged to enforce it. */\n readonly enforcedBy: MustEnforcer;\n /** Spec section this was adjudicated in. */\n readonly source: string;\n}\n\nconst must = (m: Must): Must => Object.freeze(m);\n\n/**\n * Every normative MUST in protocol v0.\n *\n * @remarks\n * Grouped by concern for readability; the conformance kit treats this as a\n * flat set. Adding an entry here without a corresponding conformance test is\n * a CI failure, by design.\n */\nexport const MUSTS = Object.freeze({\n // ---- Pairing and identity -------------------------------------------\n PAIR_ONE_USER: must({\n id: \"PAIR_ONE_USER\",\n statement:\n \"A runner token MUST be bound to exactly one user; a daemon MUST refuse \" +\n \"work not attributable to its paired user.\",\n enforcedBy: \"both\",\n source: \"byollm_001 §MUSTs\",\n }),\n PAIR_INTERACTIVE: must({\n id: \"PAIR_INTERACTIVE\",\n statement:\n \"Pairing MUST be interactive (device-code approval in the app's own \" +\n \"session); a long-lived pasted secret MUST NOT be accepted as pairing.\",\n enforcedBy: \"server\",\n source: \"byollm_001 §Endpoints.1\",\n }),\n PAIR_CODE_EXPIRES: must({\n id: \"PAIR_CODE_EXPIRES\",\n statement:\n \"An unapproved device code MUST expire and MUST NOT be redeemable after \" +\n \"expiry.\",\n enforcedBy: \"server\",\n source: \"byollm_001 §Endpoints.1\",\n }),\n\n // ---- Typed job kinds --------------------------------------------------\n KIND_TYPED_ONLY: must({\n id: \"KIND_TYPED_ONLY\",\n statement:\n \"Job kinds MUST resolve against handlers baked into the daemon. A daemon \" +\n \"MUST refuse an unknown kind rather than guess.\",\n enforcedBy: \"daemon\",\n source: \"byollm_001 §Jobs are typed data\",\n }),\n KIND_NO_CODE: must({\n id: \"KIND_NO_CODE\",\n statement:\n \"A server MUST NOT be able to convey code, a shell string, or a path to \" +\n \"execute; payloads are data handed to a model only.\",\n enforcedBy: \"daemon\",\n source: \"byollm_001 §Jobs are typed data; byollm_004 §1\",\n }),\n\n // ---- Capability and claiming -----------------------------------------\n CLAIM_REQUIRES_CAPABILITY: must({\n id: \"CLAIM_REQUIRES_CAPABILITY\",\n statement:\n \"A daemon MUST NOT be given a job whose kind is absent from its \" +\n \"advertised capability matrix.\",\n enforcedBy: \"both\",\n source: \"byollm_001 §MUSTs\",\n }),\n CAPABILITY_IS_DETECTED: must({\n id: \"CAPABILITY_IS_DETECTED\",\n statement:\n \"An advertised capability matrix MUST be the intersection of owner \" +\n \"config and detected, healthy reality — never config alone.\",\n enforcedBy: \"daemon\",\n source: \"byollm_002 §Routing\",\n }),\n CLAIM_ATOMIC: must({\n id: \"CLAIM_ATOMIC\",\n statement:\n \"Claiming MUST be atomic: a job MUST NOT be handed to two runners \" +\n \"concurrently.\",\n enforcedBy: \"server\",\n source: \"byollm_001 §Endpoints.2\",\n }),\n\n // ---- Leases -----------------------------------------------------------\n LEASE_HONORED: must({\n id: \"LEASE_HONORED\",\n statement:\n \"A daemon MUST stop work on a job whose lease it has failed to renew, \" +\n \"and MUST NOT report a result for an expired lease it no longer holds.\",\n enforcedBy: \"daemon\",\n source: \"byollm_001 §MUSTs\",\n }),\n LEASE_RECLAIMABLE: must({\n id: \"LEASE_RECLAIMABLE\",\n statement:\n \"A lease that expires un-renewed MUST make its job claimable again with \" +\n \"no loss of the job.\",\n enforcedBy: \"server\",\n source: \"byollm_001 §Endpoints.2\",\n }),\n\n // ---- Audience and offer scope ----------------------------------------\n AUDIENCE_BOTH_SIDES: must({\n id: \"AUDIENCE_BOTH_SIDES\",\n statement:\n \"A job MUST run on a daemon only if the daemon's offer scope admits the \" +\n \"job's owner AND the job's audience admits the daemon's owner.\",\n enforcedBy: \"both\",\n source: \"byollm_001 §The audience model\",\n }),\n SUBSCRIPTION_SELF_LOCK: must({\n id: \"SUBSCRIPTION_SELF_LOCK\",\n statement:\n \"A subscription-class backend's offer scope MUST be 'self' and MUST NOT \" +\n \"be widened by configuration.\",\n enforcedBy: \"daemon\",\n source: \"byollm_001 §The audience model\",\n }),\n NAMED_LOCAL_ALLOWLIST: must({\n id: \"NAMED_LOCAL_ALLOWLIST\",\n statement:\n \"A 'named' job MUST be admitted only by the daemon's own local \" +\n \"(server origin, user id) allowlist — never on the server's assertion \" +\n \"alone.\",\n enforcedBy: \"daemon\",\n source: \"byollm_001 Rev 1 §B\",\n }),\n\n REFUSAL_NOT_REOFFERED: must({\n id: \"REFUSAL_NOT_REOFFERED\",\n statement:\n \"A server MUST NOT re-offer a job to a runner that released it with \" +\n \"reason 'refused'.\",\n enforcedBy: \"server\",\n source: \"byollm_001 Rev 1 §B (loop resolved in build review)\",\n }),\n\n // ---- Revocation and cancel -------------------------------------------\n REVOCATION_HONORED: must({\n id: \"REVOCATION_HONORED\",\n statement:\n \"A revoked daemon MUST stop claiming and MUST abandon in-flight work by \" +\n \"the next heartbeat at the latest.\",\n enforcedBy: \"daemon\",\n source: \"byollm_001 §MUSTs\",\n }),\n CANCEL_HONORED: must({\n id: \"CANCEL_HONORED\",\n statement:\n \"A job id in a heartbeat response's cancel list MUST abort that job's \" +\n \"in-flight backend call and be reported as 'canceled'.\",\n enforcedBy: \"daemon\",\n source: \"byollm_001 Rev 1 §C\",\n }),\n\n // ---- Lifecycle, dependencies, delivery -------------------------------\n DEPENDS_ON_GATING: must({\n id: \"DEPENDS_ON_GATING\",\n statement:\n \"A job MUST NOT be claimable until every job in its dependsOn set has \" +\n \"reached the 'ok' state.\",\n enforcedBy: \"server\",\n source: \"byollm_001 Rev 1 §E\",\n }),\n TTL_EXPIRY: must({\n id: \"TTL_EXPIRY\",\n statement:\n \"An unclaimed job MUST become 'expired' once its TTL elapses, and the \" +\n \"TTL clock MUST start when the job becomes claimable, not at enqueue.\",\n enforcedBy: \"server\",\n source: \"byollm_001 Rev 1 §D (TTL clock resolved in build review)\",\n }),\n NO_RUNNER_SIGNAL: must({\n id: \"NO_RUNNER_SIGNAL\",\n statement:\n \"A server MUST surface noRunnerAvailable when no runner with matching \" +\n \"capability has heartbeated within the liveness window, and MUST NOT \" +\n \"raise it for a job still blocked on dependencies.\",\n enforcedBy: \"server\",\n source: \"byollm_001 Rev 1 §D\",\n }),\n RESULT_IDEMPOTENT: must({\n id: \"RESULT_IDEMPOTENT\",\n statement:\n \"Result submission MUST be idempotent by job id; the first terminal \" +\n \"outcome wins and later submissions MUST NOT change it.\",\n enforcedBy: \"server\",\n source: \"byollm_001 §Endpoints.4\",\n }),\n RESULT_PROVENANCE: must({\n id: \"RESULT_PROVENANCE\",\n statement:\n \"A result from a non-'self' job MUST carry its provenance (audience and \" +\n \"runner) to the delivery seam so an app never treats volunteer output \" +\n \"as first-party.\",\n enforcedBy: \"server\",\n source: \"byollm_003 Rev 1 §Return-trip\",\n }),\n\n // ---- The trust surface -------------------------------------------------\n INGRESS_LOGGED_BEFORE_EXECUTION: must({\n id: \"INGRESS_LOGGED_BEFORE_EXECUTION\",\n statement:\n \"Every executed prompt MUST be appended to the local ingress log before \" +\n \"execution begins.\",\n enforcedBy: \"daemon\",\n source: \"byollm_001 §MUSTs\",\n }),\n\n // ---- Execution isolation (byollm_004) ---------------------------------\n NO_SHELL_INTERPOLATION: must({\n id: \"NO_SHELL_INTERPOLATION\",\n statement:\n \"Process-class backends MUST be invoked with a fixed argv array and the \" +\n \"payload delivered on stdin; payload text MUST NOT reach a command line.\",\n enforcedBy: \"daemon\",\n source: \"byollm_004 §2\",\n }),\n NO_PAYLOAD_ROUTING: must({\n id: \"NO_PAYLOAD_ROUTING\",\n statement:\n \"Model, backend, base URL, and flags MUST come from owner config only; \" +\n \"a payload MUST NOT influence any of them.\",\n enforcedBy: \"daemon\",\n source: \"byollm_004 §2\",\n }),\n STRIPPED_CHILD_ENV: must({\n id: \"STRIPPED_CHILD_ENV\",\n statement:\n \"Process-class children MUST spawn with an allowlisted environment, a \" +\n \"scratch cwd, no inherited descriptors beyond std streams, and hard \" +\n \"timeout and output-size caps.\",\n enforcedBy: \"daemon\",\n source: \"byollm_004 §2\",\n }),\n HTTP_BASE_URL_SAFE: must({\n id: \"HTTP_BASE_URL_SAFE\",\n statement:\n \"HTTP-class backends MUST send requests only to the owner-configured \" +\n \"base URL and MUST refuse base URLs resolving to cloud-metadata or \" +\n \"link-local addresses.\",\n enforcedBy: \"daemon\",\n source: \"byollm_004 Rev 1 §Backend taxonomy\",\n }),\n OUTPUT_INERT: must({\n id: \"OUTPUT_INERT\",\n statement:\n \"Returned text MUST be treated as inert bytes: never evaluated, never \" +\n \"written to a payload-named path, never interpolated into a shell or \" +\n \"into terminal control sequences when logged.\",\n enforcedBy: \"daemon\",\n source: \"byollm_004 §2\",\n }),\n COMMUNITY_BUDGETS: must({\n id: \"COMMUNITY_BUDGETS\",\n statement:\n \"Jobs whose owner is not the daemon's owner MUST be subject to the \" +\n \"owner's rate limits, daily cap, and resource budget.\",\n enforcedBy: \"daemon\",\n source: \"byollm_004 §4\",\n }),\n} as const satisfies Record<string, Must>);\n\n/** The id of any normative MUST. */\nexport type MustId = keyof typeof MUSTS;\n\n/** All MUST ids, for coverage checks. */\nexport const MUST_IDS = Object.freeze(Object.keys(MUSTS) as MustId[]);\n","import { z } from \"zod\";\nimport { OfferScope } from \"./audience.js\";\nimport { BackendClass, BackendIdSchema } from \"./backends.js\";\nimport { ClaimedJob, JobOutcome } from \"./job.js\";\nimport { JobKind } from \"./kinds.js\";\n\n/** Protocol version carried on every request; servers refuse what they can't speak. */\nexport const PROTOCOL_VERSION = \"0\" as const;\n\n/** The path prefix all endpoints mount under. */\nexport const PROTOCOL_PREFIX = \"/byollm\" as const;\n\n/** The five endpoint names, in the order byollm_001 lists them. */\nexport const ENDPOINTS = Object.freeze([\n \"pair\",\n \"claim\",\n \"heartbeat\",\n \"result\",\n \"release\",\n] as const);\nexport type Endpoint = (typeof ENDPOINTS)[number];\n\n/**\n * One entry of the capability matrix: a kind this daemon can actually serve,\n * right now, with the backend and model that would serve it.\n *\n * Derived from owner config intersected with detected reality\n * ({@link MUSTS.CAPABILITY_IS_DETECTED}) — a configured-but-unreachable\n * backend must not appear here. Carries `backendClass` so the app can tell\n * whether a result came from a sandboxed spawn or an HTTP call\n * (byollm_001 Rev 1 §A).\n */\nexport const Capability = z\n .object({\n kind: JobKind,\n backendId: BackendIdSchema,\n backendClass: BackendClass,\n model: z.string().min(1),\n offerScope: OfferScope,\n })\n .strict();\nexport type Capability = z.infer<typeof Capability>;\n\n/** The capability matrix a daemon advertises. */\nexport const CapabilityMatrix = z.array(Capability);\nexport type CapabilityMatrix = z.infer<typeof CapabilityMatrix>;\n\n// ---------------------------------------------------------------------------\n// 1. POST /byollm/pair — device-code flow\n// ---------------------------------------------------------------------------\n\n/**\n * Pairing is a device-code exchange, not a pasted secret\n * ({@link MUSTS.PAIR_INTERACTIVE}). The daemon starts a pairing, shows the\n * user a short code and a URL, and polls until the user approves it inside\n * the app's own authenticated session. Nothing listens on the user's machine\n * and nothing works over a copied string alone.\n */\nexport const PairStartRequest = z\n .object({\n protocolVersion: z.literal(PROTOCOL_VERSION),\n action: z.literal(\"start\"),\n daemon: z.object({\n version: z.string().min(1),\n /** Shown in the app's runner list so a user can tell their machines apart. */\n label: z.string().min(1).max(120),\n platform: z.enum([\"darwin\", \"linux\", \"win32\"]),\n }),\n capabilities: CapabilityMatrix,\n })\n .strict();\nexport type PairStartRequest = z.infer<typeof PairStartRequest>;\n\nexport const PairStartResponse = z\n .object({\n /** Secret the daemon polls with. Never shown to the user. */\n deviceCode: z.string().min(20),\n /** Short code the user reads and confirms in the browser. */\n userCode: z.string().min(4).max(16),\n /** Where the user approves. Must be on the server's own origin. */\n verificationUrl: z.url(),\n /** Epoch ms after which the code is dead ({@link MUSTS.PAIR_CODE_EXPIRES}). */\n expiresAt: z.number().int().positive(),\n /** How often the daemon may poll. */\n pollIntervalMs: z.number().int().min(500).max(60_000),\n })\n .strict();\nexport type PairStartResponse = z.infer<typeof PairStartResponse>;\n\nexport const PairPollRequest = z\n .object({\n protocolVersion: z.literal(PROTOCOL_VERSION),\n action: z.literal(\"poll\"),\n deviceCode: z.string().min(20),\n })\n .strict();\nexport type PairPollRequest = z.infer<typeof PairPollRequest>;\n\nexport const PairPollResponse = z.discriminatedUnion(\"status\", [\n z.object({ status: z.literal(\"pending\") }).strict(),\n z.object({ status: z.literal(\"denied\") }).strict(),\n z.object({ status: z.literal(\"expired\") }).strict(),\n z\n .object({\n status: z.literal(\"approved\"),\n /** Bearer token for every later call. Scoped to exactly one user. */\n runnerToken: z.string().min(20),\n runnerId: z.string().min(1),\n /** The app's id for the approving user — this daemon's owner forever. */\n owner: z.string().min(1),\n /** Display name for the trust UI, if the app offers one. */\n ownerLabel: z.string().optional(),\n })\n .strict(),\n]);\nexport type PairPollResponse = z.infer<typeof PairPollResponse>;\n\nexport const PairRequest = z.discriminatedUnion(\"action\", [\n PairStartRequest,\n PairPollRequest,\n]);\nexport type PairRequest = z.infer<typeof PairRequest>;\n\n// ---------------------------------------------------------------------------\n// 2. POST /byollm/claim\n// ---------------------------------------------------------------------------\n\nexport const ClaimRequest = z\n .object({\n protocolVersion: z.literal(PROTOCOL_VERSION),\n runnerId: z.string().min(1),\n /** Re-sent on every claim so a server never matches against a stale matrix. */\n capabilities: CapabilityMatrix,\n /** Upper bound on jobs to return; the server may return fewer. */\n max: z.number().int().min(1).max(64),\n })\n .strict();\nexport type ClaimRequest = z.infer<typeof ClaimRequest>;\n\nexport const ClaimResponse = z\n .object({\n jobs: z.array(ClaimedJob),\n /** Lease duration granted, so the daemon knows its renewal deadline. */\n leaseMs: z.number().int().positive(),\n })\n .strict();\nexport type ClaimResponse = z.infer<typeof ClaimResponse>;\n\n// ---------------------------------------------------------------------------\n// 3. POST /byollm/heartbeat\n// ---------------------------------------------------------------------------\n\nexport const HeartbeatRequest = z\n .object({\n protocolVersion: z.literal(PROTOCOL_VERSION),\n runnerId: z.string().min(1),\n daemonVersion: z.string().min(1),\n capabilities: CapabilityMatrix,\n /** Jobs this daemon believes it holds; the server renews their leases. */\n activeJobIds: z.array(z.string().min(1)),\n /** True while the owner has the daemon paused; the server stops offering work. */\n paused: z.boolean(),\n })\n .strict();\nexport type HeartbeatRequest = z.infer<typeof HeartbeatRequest>;\n\nexport const HeartbeatResponse = z\n .object({\n /** Once true, the daemon stops claiming and abandons in-flight work. */\n revoked: z.boolean(),\n /**\n * Per-job cancel (byollm_001 Rev 1 §C). The daemon aborts these jobs'\n * in-flight backend calls and reports them `canceled`.\n */\n cancel: z.array(z.string().min(1)),\n /** Jobs whose leases were renewed, with their new expiry. */\n leases: z.array(\n z\n .object({\n jobId: z.string().min(1),\n expiresAt: z.number().int().positive(),\n })\n .strict(),\n ),\n /**\n * Jobs the daemon thinks it holds but the server has reassigned or\n * expired. The daemon must stop work on these and not report results.\n */\n lost: z.array(z.string().min(1)),\n /** Server clock, so a daemon with a skewed clock still honors leases. */\n serverTime: z.number().int().positive(),\n })\n .strict();\nexport type HeartbeatResponse = z.infer<typeof HeartbeatResponse>;\n\n// ---------------------------------------------------------------------------\n// 4. POST /byollm/result\n// ---------------------------------------------------------------------------\n\nexport const ResultRequest = z\n .object({\n protocolVersion: z.literal(PROTOCOL_VERSION),\n runnerId: z.string().min(1),\n jobId: z.string().min(1),\n outcome: JobOutcome,\n /** Which model actually served it, for the result's provenance. */\n model: z.string().min(1),\n backendClass: BackendClass,\n /** Wall-clock milliseconds the backend call took. */\n durationMs: z.number().int().nonnegative(),\n })\n .strict();\nexport type ResultRequest = z.infer<typeof ResultRequest>;\n\nexport const ResultResponse = z\n .object({\n /**\n * False when the submission lost an idempotency race or the lease was\n * already gone — the daemon should discard, not retry\n * ({@link MUSTS.RESULT_IDEMPOTENT}).\n */\n accepted: z.boolean(),\n /** The job's state after this submission. */\n state: z.string().min(1),\n })\n .strict();\nexport type ResultResponse = z.infer<typeof ResultResponse>;\n\n// ---------------------------------------------------------------------------\n// 5. POST /byollm/release\n// ---------------------------------------------------------------------------\n\nexport const ReleaseRequest = z\n .object({\n protocolVersion: z.literal(PROTOCOL_VERSION),\n runnerId: z.string().min(1),\n jobIds: z.array(z.string().min(1)),\n /**\n * Why, so the app's runner list can say something true.\n *\n * `refused` is load-bearing, not cosmetic: the server cannot evaluate a\n * daemon's *local* `named` allowlist (§4.2), so it may legitimately offer\n * a job this daemon then declines. The server MUST record the refusal and\n * stop offering that job to that runner, or the pair would spin between\n * claim and release forever.\n */\n reason: z.enum([\"shutdown\", \"pause\", \"revoked\", \"backend-down\", \"refused\"]),\n })\n .strict();\nexport type ReleaseRequest = z.infer<typeof ReleaseRequest>;\n\nexport const ReleaseResponse = z\n .object({\n released: z.array(z.string().min(1)),\n })\n .strict();\nexport type ReleaseResponse = z.infer<typeof ReleaseResponse>;\n\n// ---------------------------------------------------------------------------\n// Errors\n// ---------------------------------------------------------------------------\n\n/**\n * Wire error codes.\n *\n * byollm_002 requires that \"server unreachable\", \"revoked\", \"no matching\n * work\" and \"backend down\" never share a message. Distinct codes here are how\n * the daemon can tell three of those apart; the fourth is a transport failure\n * with no response at all.\n */\nexport const WireErrorCode = z.enum([\n \"bad-request\",\n \"unsupported-protocol-version\",\n \"unauthorized\",\n \"revoked\",\n \"not-found\",\n \"rate-limited\",\n \"server-error\",\n]);\nexport type WireErrorCode = z.infer<typeof WireErrorCode>;\n\nexport const WireError = z\n .object({\n error: WireErrorCode,\n message: z.string().min(1),\n /** Seconds; mirrors Retry-After for `rate-limited` and `server-error`. */\n retryAfter: z.number().int().nonnegative().optional(),\n })\n .strict();\nexport type WireError = z.infer<typeof WireError>;\n\n/** HTTP status each error code is served with. */\nexport const ERROR_STATUS: Readonly<Record<WireErrorCode, number>> =\n Object.freeze({\n \"bad-request\": 400,\n \"unsupported-protocol-version\": 400,\n unauthorized: 401,\n revoked: 403,\n \"not-found\": 404,\n \"rate-limited\": 429,\n \"server-error\": 500,\n });\n"],"mappings":"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","names":["z","z","z","z","z","z","z"]}
package/package.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "@byollm/protocol",
3
+ "version": "0.1.0-alpha.0",
4
+ "description": "The BYOLLM wire contract — types, zod schemas, and the audience rules both the daemon and server enforce. ALPHA: under active development.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "import": "./dist/index.js"
11
+ }
12
+ },
13
+ "main": "./dist/index.js",
14
+ "types": "./dist/index.d.ts",
15
+ "files": [
16
+ "dist",
17
+ "README.md"
18
+ ],
19
+ "engines": {
20
+ "node": ">=22.12"
21
+ },
22
+ "dependencies": {
23
+ "zod": "^4.4.3"
24
+ },
25
+ "publishConfig": {
26
+ "access": "public"
27
+ },
28
+ "homepage": "https://byo-llm.com",
29
+ "scripts": {
30
+ "build": "tsup",
31
+ "clean": "rm -rf dist *.tsbuildinfo"
32
+ }
33
+ }