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); }