Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
tools (`tools.ts`), opaque capability handles (`capabilities.ts`) and the
bounded durable mailbox driver (`mailbox.ts`), the named durable process
supervisor (`process.ts`), the provider-neutral
typed-decision layer (`decisions.ts`) with the TypeSafe Jev adapter
(`jev.ts`), cross-platform
typed-decision layer (`decisions.ts`) with the Cloudflare Clef adapter
(`clef.ts`, native `clef.rs`) and explicit legacy Jev adapter (`jev.ts`), cross-platform
credential custody (`credentials.ts`), embeddings (`embeddings.ts`) and
the derived semantic index plus recall executor (`semantic.ts`), foundry
evaluation and search (`foundry.ts`, `search.ts`) with the habitat-wide
Expand Down
71 changes: 52 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -522,15 +522,16 @@ Cell kinds:
question map (`{"answers":{…}}`), the effect request carries `questions`,
and the provider must return exactly the declared answers. Decision
executors serve `decide` and `classifier` cells only — they can never
generate agent output or approve a gate. Jev (TypeSafe `systemone`) is
the first such provider, admitted with `--jev`; its key lives in
`TYPESAFE_API_KEY` or the local vault via `algal auth jev`.
generate agent output or approve a gate. Cloudflare Clef serves these
decisions when you select `--clef` (`clef` by default, or `clef-flash`).
Paid inference is opt-in. Set `CLOUDFLARE_ACCOUNT_ID` and
`CLOUDFLARE_API_TOKEN`; `CLOUDFLARE_AUTH_TOKEN` is a token alias.
- `recall` — an expression-derived semantic query over a host-owned index,
recorded as an ordinary effect. `out` carries bounded ranked hits; when the
first hit names a value-store object, `ref` carries its `sha256:` token
directly into `load`. Empty recall is successful and leaves ref consumers
skipped. Optional `rerank:{route,take?}` sends one recorded `noul` relevance
question per hit to a decision provider such as Jev, then reorders the exact
question per hit to a decision provider such as Clef, then reorders the exact
source records without summarizing them. The request binds query, `k`, and
embedder; replay serves the recorded hits and decisions without consulting a
mutable index.
Expand Down Expand Up @@ -794,7 +795,7 @@ contract data: it changes nothing about digests, receipts, or replay.
`recall` cell makes the same capability available inside an organism through
a recorded effect. Its bounded expression produces the query, `out` exposes
ranked text and provenance, and a top value hit also emits `ref` for direct
`load` resolution. Add `rerank:{route:{provider:"jev"},take:…}` to score each
`load` resolution. Add `rerank:{route:{provider:"clef"},take:…}` to score each
dynamic hit through the typed decision seam before choosing that top ref; the
original hit records remain intact and the `decide` answers ride the receipt.
Index-backed recall is deliberately not effect-cached; replay comes from the
Expand All @@ -812,28 +813,60 @@ bun run cli run organism-with-recall.json --dir .algal --recall local
When one organism combines recall with another effect provider, give the
recall cell an explicit route such as `{"provider":"memory"}` and its rerank
policy a decision route such as `{"provider":"judge"}`. The Bun `--executors`
map can admit `"memory":"recall"` and `"judge":"jev"`; native
map can attach `"memory":"recall"` and `"judge":"clef"`; native
`algal.host.v1` entries use
`"memory":{"kind":"recall","dir":".algal","embedder":"local"}` and a
separate Jev backend. The derived index implementations use different
separate `"judge":{"kind":"clef"}` backend. The derived index implementations use different
disposable storage (SQLite in TypeScript, JSONL natively) but produce the same
local vectors and hybrid ranking.

## Provider credentials

Provider keys never enter manifests, receipts, digests, or logs — they resolve
at the executor boundary only. `auth` vaults them locally cross-platform
(macOS Keychain, libsecret, Windows DPAPI, or — when no vault is available —
a plaintext file under `~/.algal/credentials` (or `$ALGAL_HOME`) with mode
0600; both CLIs print a warning when they fall back to it); the provider env var always works as a CI
escape hatch.
The Cloudflare Clef CLIs read `CLOUDFLARE_ACCOUNT_ID` (32 lowercase
hexadecimal characters) and `CLOUDFLARE_API_TOKEN` from the environment.
The token may also come from `CLOUDFLARE_AUTH_TOKEN`. Library hosts may
supply an explicit in-memory credential or async resolver. Tokens never enter manifests, saved
runs, configuration digests, or logs. ALGAL does not save Cloudflare tokens
or reuse a TypeSafe key. `doctor --clef` checks configuration without an API
call; inference starts only when you attach a Clef executor.

```sh
bun run cli auth jev # vault a TypeSafe Jev key (TYPESAFE_API_KEY)
bun run cli auth jev --status # where the key resolves from (hint only)
bun run cli doctor --jev # live one-question check against systemone
bun run cli auth clef --status
bun run cli doctor --clef
bun run cli run examples/model-router.algal.json --args examples/model-router.args.json --clef
```

Both CLIs accept `--clef clef-flash`. For embedded images, pass
`--images images.json` with `--clef`; the file contains an array of PNG,
JPEG or WebP data URLs or `{content_type,base64}` objects. Limits are 4
images, 4 MiB per image and 8 MiB total after base64 decoding into file
bytes, 16 megapixels per image, and 13 MiB for the JSON file and request
body. Native `algal.host.v1` files may configure an `images` array on a Clef
backend, but the entire host file has a separate 1 MiB limit, including
base64 text. Use `--clef --images` for the larger image budget.

Normal manifest runs use only executor-configured images; a manifest
cannot supply image files or implicitly attach source code. Direct adapter
calls can pass images through `clefAsker.ask(state, questions, signal,
images)`, TypeScript `EffectRequest.images`, or native `clef::prepare`.
These are low-level host interfaces, not manifest fields. Only one image
source is accepted. Remote URLs, invalid base64, mismatched signatures,
truncated containers and exceeded limits fail before credential resolution
or dispatch. The checks inspect container structure and dimensions, not
pixel decoding or PNG checksums; they do not establish that every image
payload is decodable. See [executor configuration](docs/executors.md#cloudflare-clef).
ALGAL rejects oversized state instead of truncating it; the provider's
context limits also apply. Clef requires nonempty
instructions, question IDs matching `[A-Za-z0-9_.-]{1,100}`, at least two
choice options, and 2 to 10 score levels. ALGAL also limits choices to 32.
Responses must match the questions and selected model, with valid probability
mass, confidence, score legends and token counts.

The explicit `--jev`, `jevAsker`, `jevExecutor` and native `kind:"jev"`
paths remain for legacy integrations. They use their own TypeSafe credential
and never supply Cloudflare credentials. Historical Jev runs replay offline
without contacting either provider.

## Foundry: select organisms by evidence

A foundry evaluates a bounded population against explicit train and validation
Expand Down Expand Up @@ -943,9 +976,9 @@ algal bench verify bench-report.json --dir .algal

A `algal.bench.config.v1` file names case `args`/`expect` pairs and systems
whose `executors` map names to `gateway:<provider/model>` (Vercel AI Gateway),
`scripted:<file>`, or `cmd:<command>` specs. The Bun CLI also accepts
`jev[:<model>]` and `recall[:<embedder>]`; the native CLI accepts `apple` for
the on-device bridge and admits Jev/recall through `algal.host.v1`. Named entries answer `route.preset` /
`clef[:<model>]`, `scripted:<file>`, or `cmd:<command>` specs. The Bun CLI
also accepts `recall[:<embedder>]`; the native CLI accepts `apple` for the
on-device bridge and attaches recall through `algal.host.v1`. Named entries answer `route.preset` /
`route.provider`; the fallback is the first listed entry (in the native CLI,
the first name alphabetically). The report records per-case results, work,
token usage, per-model effect attribution, and the non-dominated pareto set on
Expand Down
58 changes: 48 additions & 10 deletions cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,14 @@ async function jevSpecExecutor(spec: string): Promise<Executor | undefined> {
});
}

async function clefSpecExecutor(spec: string, images?: import("./src/clef").ClefImage[]): Promise<Executor | undefined> {
if (spec !== "clef" && !spec.startsWith("clef:")) return undefined;
const { clefExecutor } = await import("./src/clef");
const model = spec === "clef" ? "clef" : spec.slice(5);
if (model !== "clef" && model !== "clef-flash") usageError("Clef model must be clef or clef-flash");
return clefExecutor({ model, ...(images !== undefined ? { images } : {}) });
}

async function recallSpecExecutor(spec: string, dir: string): Promise<Executor | undefined> {
if (spec !== "recall" && !spec.startsWith("recall:")) return undefined;
const embedderSpec = spec === "recall" ? "local" : spec.slice(7);
Expand Down Expand Up @@ -183,7 +191,12 @@ usage:
--base-url <url> --model <model> OpenAI-compatible endpoint (HTTPS or loopback HTTP)
--credential-env <name> endpoint credential environment variable (optional)
--response-format <format> json_schema (default), json_object, or prompt
--jev [model] TypeSafe Jev decision executor — serves
--clef [clef|clef-flash] Cloudflare Clef decision executor (paid, opt-in)
set CLOUDFLARE_ACCOUNT_ID and CLOUDFLARE_API_TOKEN
(CLOUDFLARE_AUTH_TOKEN is also accepted)
--images <file> JSON array of embedded PNG/JPEG/WebP images;
requires --clef; max 4, 4 MiB each, 8 MiB total
--jev [model] Legacy TypeSafe Jev decision executor — serves
decide and classifier cells (never gates:
approvals stay host/policy-routed)
--recall [embedder] derived-index recall executor; embedder is
Expand Down Expand Up @@ -379,7 +392,7 @@ usage:
returns only declared interface outputs.
options mirror algal run: --args, --responses,
--executor-cmd, --executor-profile, --gateway-model,
--jev, --recall,
--clef, --images, --jev, --recall,
--executors, --modules, --tools, --cache-effects, --dir
algal tool-def <manifest.json> [--modules <dir>]
print an OpenAI/Anthropic tool definition for the
Expand All @@ -402,11 +415,13 @@ usage:
receipts-touching-capability <class>,
unevaluated-revisions, largest-work,
process-status, kinds
algal auth clef --status check environment-only Cloudflare credentials
algal auth jev [--status | --forget | --stdin | --clipboard]
vault a provider credential locally — keychain
when available, permission-checked file otherwise;
never echoes the key
algal doctor [--jev] runtime and provider availability check
algal doctor [--clef] runtime and Cloudflare configuration check (no API call)
algal doctor --jev legacy Jev live connectivity check
algal --version | --help

Source diagnostics (all commands that load .algal files):
Expand Down Expand Up @@ -857,7 +872,7 @@ async function resolveExecutors(
usageError("--base-url and --model must be supplied together");
if (baseUrl === undefined && (credentialEnv !== undefined || responseFormat !== undefined))
usageError("--credential-env and --response-format require --base-url and --model");
if (baseUrl !== undefined && ["responses", "executor-cmd", "gateway-model", "jev", "recall"].some(key => flags[key] !== undefined))
if (baseUrl !== undefined && ["responses", "executor-cmd", "gateway-model", "clef", "jev", "recall"].some(key => flags[key] !== undefined))
usageError("choose one default executor; --base-url cannot be combined with another provider");
if (responseFormat !== undefined && !["json_schema", "json_object", "prompt"].includes(responseFormat))
usageError("--response-format must be json_schema, json_object, or prompt");
Expand Down Expand Up @@ -903,6 +918,14 @@ async function resolveExecutors(
const { vercelGatewayExecutor } = await import("./src/gateway");
executors.push(vercelGatewayExecutor({ model }));
}
if (flags.images !== undefined && flags.clef === undefined) usageError("--images requires --clef");
if (flags.clef !== undefined) {
if (["responses", "executor-cmd", "gateway-model", "jev", "recall"].some(key => flags[key] !== undefined)) usageError("choose one default executor; --clef cannot be combined with another provider");
const { validateClefImages, CLEF_IMAGE_LIMITS } = await import("./src/clef");
const imageFile = artifactFlag(flags, "images");
const images = imageFile !== undefined ? validateClefImages(await readJsonBounded(imageFile, CLEF_IMAGE_LIMITS.maxBodyBytes, "Clef images")) : undefined;
executors.push((await clefSpecExecutor(typeof flags.clef === "string" ? `clef:${flags.clef}` : "clef", images))!);
}
if (flags.jev !== undefined) {
executors.push((await jevSpecExecutor(typeof flags.jev === "string" ? `jev:${flags.jev}` : "jev"))!);
}
Expand All @@ -922,6 +945,8 @@ async function resolveExecutors(
`executors.${name} must be a shell command string`,
);
}
const clef = await clefSpecExecutor(cmd);
if (clef !== undefined) { executors.push(named(name, clef)); continue; }
const jev = await jevSpecExecutor(cmd);
if (jev !== undefined) {
executors.push(named(name, jev));
Expand Down Expand Up @@ -2787,6 +2812,8 @@ async function main(): Promise<number> {
const { vercelGatewayExecutor } = await import("./src/gateway");
return named(id, vercelGatewayExecutor({ model: spec.slice("gateway:".length) }));
}
const clef = await clefSpecExecutor(spec);
if (clef !== undefined) return named(id, clef);
const jev = await jevSpecExecutor(spec);
if (jev !== undefined) return named(id, jev);
const recall = await recallSpecExecutor(spec, dir);
Expand All @@ -2807,7 +2834,7 @@ async function main(): Promise<number> {
}
throw new AlgalError(
"PARSE_FAILED",
`bench executor "${id}": unknown spec (want gateway:<model>, jev[:<model>], recall[:<embedder>], scripted:<file>, or cmd:<command>)`,
`bench executor "${id}": unknown spec (want gateway:<model>, clef[:<model>], jev[:<model>], recall[:<embedder>], scripted:<file>, or cmd:<command>)`,
);
};
const systems: BenchSystem[] = [];
Expand Down Expand Up @@ -3731,7 +3758,8 @@ async function main(): Promise<number> {

case "auth": {
const provider = positional[0];
if (provider !== "jev") usageError("algal auth <jev> [--status|--forget|--stdin|--clipboard]");
if (provider !== "jev" && provider !== "clef") usageError("algal auth clef --status or algal auth jev [--status|--forget|--stdin|--clipboard]");
if (provider === "clef" && flags.status === undefined) usageError("Clef credentials are environment-only; set CLOUDFLARE_ACCOUNT_ID and CLOUDFLARE_API_TOKEN (CLOUDFLARE_AUTH_TOKEN is also accepted)");
const { credentialStatus, forgetCredential, providerSpec, storeCredential } = await import("./src/credentials");
if (flags.status !== undefined) {
out((await credentialStatus(provider)) as unknown as JsonObject);
Expand Down Expand Up @@ -3769,6 +3797,16 @@ async function main(): Promise<number> {
}

case "doctor": {
if (flags.clef !== undefined) {
const { credentialStatus } = await import("./src/credentials");
const { clefEndpoint } = await import("./src/clef");
const credential = await credentialStatus("clef");
let accountConfigured = false;
try { clefEndpoint(process.env.CLOUDFLARE_ACCOUNT_ID ?? ""); accountConfigured = true; } catch { accountConfigured = false; }
const configured = accountConfigured && credential.configured;
out({ provider: "clef", configured, accountConfigured, credential: credential as unknown as JsonValue, liveChecked: false });
return configured ? 0 : 1;
}
if (flags.jev !== undefined) {
const { credentialResolver, credentialStatus, providerSpec } = await import("./src/credentials");
const { jevAsker } = await import("./src/jev");
Expand Down Expand Up @@ -3809,12 +3847,12 @@ async function main(): Promise<number> {
}
}
if (humanReport(process.argv.slice(2))) {
const jevEnv = process.env.TYPESAFE_API_KEY !== undefined && process.env.TYPESAFE_API_KEY !== "";
const clefEnv = Boolean(process.env.CLOUDFLARE_API_TOKEN || process.env.CLOUDFLARE_AUTH_TOKEN);
printDoctor([
["ok", `ALGAL ${PACKAGE_VERSION} is ready (Bun reference runtime on ${platformName()}).`],
jevEnv
? ["ok", "Jev key found in TYPESAFE_API_KEY. Test it: algal doctor --jev"]
: ["skip", "Jev decisions: not checked. Test a saved key: algal doctor --jev"],
clefEnv
? ["ok", "Cloudflare token found. Check configuration: algal doctor --clef"]
: ["skip", "Clef decisions: not configured. Set CLOUDFLARE_ACCOUNT_ID and CLOUDFLARE_API_TOKEN."],
], undefined, "algal examples");
return 0;
}
Expand Down
Loading
Loading