Programmatic agents
ForgeLore TypeScript SDK
Build typed tools and automation against the same API surface used by the ForgeLore app, CLI, and MCP server.
Install
$npm install @nortycary/forgelore-sdk
Create a client
import { ForgeLoreClient, unwrap } from "@nortycary/forgelore-sdk";
const forgelore = new ForgeLoreClient({
token: process.env.FORGELORE_AGENT_TOKEN,
});
Typed JSON envelopes
Responses use `ok`, `data`, `error`, and `requestId`; `unwrap`, `isApiError`, and `classifyRetry` keep recovery explicit.
Agent discovery
Use `validateSession`, `getAgentManifest`, `discoverEnvironment`, `listBillingPlans`, and `listAgentWorkflows` before choosing operations. `agentSession` and `billingPlans` remain available as compatibility aliases.
Safety in code
Dry-run support, idempotency headers, pagination helpers, and redaction utilities are available for agent-relevant workflows.
Native Lore remains native
Use ForgeLore SDK for control-plane workflows and the official Lore CLI for repository content operations.
Autonomous discovery flow
const manifest = await forgelore.getAgentManifest();
const session = await forgelore.validateSession();
const plans = await forgelore.listBillingPlans();
const repos = await forgelore.listRepositoriesPage({ limit: 25 });
const repoId = repos.ok ? repos.data.repositories[0]?.id : undefined;
if (repoId) {
const state = await forgelore.repos(repoId).inspect();
const locks = await forgelore.repos(repoId).locks.list({ limit: 50 });
const diff = await forgelore.repos(repoId).semanticDiff({
base: "main",
head: "feature/lighting",
mode: "semantic",
});
}
Dry-run a lock before editing
await forgelore.repos(repoId).locks.create({
path: "Content/Maps/Arena.umap",
reason: "Lighting pass",
dryRun: true,
idempotencyKey: "lock-arena-lighting",
});
Iterate paginated data
const repo = forgelore.repos(repoId);
for await (const file of repo.listAllFiles({ limit: 100 })) {
console.log(file.path, file.lockStatus);
}
Recover from errors
import { classifyRetry, isApiError, isRetryableError } from "@nortycary/forgelore-sdk";
const response = await forgelore.repos(repoId).locks.create({
path: "Content/Maps/Arena.umap",
reason: "Lighting pass",
idempotencyKey: "lock-arena-lighting",
});
if (isApiError(response)) {
const retry = classifyRetry(response);
console.log(response.requestId, retry.safeToRetry || isRetryableError(response), retry.nextAction);
}