# @atbash/sdk

TypeScript SDK for Atbash — the safety layer that evaluates AI agent actions against operator-defined policies before execution.

## Installation

```bash
npm install @atbash/sdk
```

Requires Node.js 18+. Server-side only — private keys are used for local signing and must never be exposed to browsers.

## Quickstart

```ts
import { Atbash } from "@atbash/sdk";

// 1. Construct with your agent's private key.
//    The SDK validates the key and derives the matching public key.
const atbash = new Atbash(process.env.ATBASH_AGENT_KEY!, {
  orgName: "my_org",
});

// 2. Submit an action for judgment, before executing it.
//    The SDK signs the transaction locally and sends it to the judge API.
//    The private key stays on your machine — never sent over HTTP.
const result = await atbash.judgeAction(
  "Transfer $50,000 to external wallet 0xabc",
  "Outbound AML check — new recipient, over threshold",
);

// 3. Enforce the verdict
switch (result.verdict) {
  case "ALLOW":
    // Proceed with the action
    break;
  case "HOLD":
    // Held — operator must approve in the dashboard
    console.log("Held for review:", result.toolCallId);
    break;
  case "BLOCK":
    // Refused — agent is jailed in Enforcement tier
    throw new Error(`Blocked: ${result.reason}`);
}
```

Before this works, the agent must be onboarded at [atbash.ai](https://atbash.ai/) — assigned to an org, with a policy pack attached, and the org on an active subscription plan.

## How it works

`judgeAction()` performs a two-step flow:

1. **Sign locally** — signs the request using the agent's private key. The key never leaves your machine.
2. **Request verdict** — sends the signed request and agent pubkey to the Atbash judge API. The server broadcasts it to the Chromia blockchain and returns a verdict.

## Don't have an agent yet?

Two ways to create an agent:

1. **Dashboard (recommended)** — create an agent at [atbash.ai/risk-engine/agents](https://atbash.ai/risk-engine/agents). The dashboard generates the keypair, assigns the agent to your org, and lets you attach a policy pack — all in one step.

2. **Programmatic** — generate a keypair locally, then onboard it via the dashboard:

   ```ts
   import { generateKeypair } from "@atbash/sdk";
   const { privKey, pubKey } = generateKeypair();
   console.log("Save this private key somewhere safe:", privKey);
   ```

   Paste the public key into the **Onboard agent** form on the dashboard, assign it to an org, and attach a policy pack before calling `judgeAction`.

## Secret storage

- Load the private key from an environment variable (`ATBASH_AGENT_KEY`) or a secret manager — never hardcode it.
- Never commit `.env` files containing the key.
- If a key leaks, stop using it and create a new agent in the dashboard.

## Verdicts

Every `judgeAction` call returns one of three verdicts:

| Verdict | Meaning | What your code should do |
|---|---|---|
| `ALLOW` | Action is within policy | Proceed with execution |
| `HOLD`  | Requires operator review | Pause — poll `getJudgmentStatus` until resolved |
| `BLOCK` | Violates a red line | Abort — agent is jailed in Enforcement tier |

> **NB:** If your org has no active subscription, the judge returns `"No verdict"` — actions are logged on-chain for the audit trail but not evaluated by an AI provider. Assign a plan at [atbash.ai/risk-engine/settings](https://atbash.ai/risk-engine/settings) for active verdicts.

## API

The `Atbash` class is the main entry point. Construct it once with your agent's private key and (optionally) a default `orgName`, then call methods on it.

### Operations

| Method | Use case |
|---|---|
| `judgeAction(action, context, opts?)` | Sign locally + request a verdict from the judge API |

### Queries

Read-only methods that read from the Chromia blockchain and dashboard.

| Method | Use case |
|---|---|
| `checkAgentExists(pubkey?)` | Check if an agent is onboarded before signing |
| `getJudgmentStatus(judgmentId, pubkey)` | Poll whether a held action has been approved or rejected |
| `getToolCalls(maxCount)` | List recent tool calls across all agents |
| `getOrgToolCalls(orgName, maxCount)` | List tool calls for a specific org |
| `getAgentToolCalls(pubkey, maxCount)` | List tool calls for a specific agent |
| `getToolCallCount()` | Total number of tool calls on-chain |
| `getToolCallFull(toolCallId)` | Full details of a single tool call |
| `getOrgTierInfo(orgName)` | Check an org's tier and whether verdicts are enabled |
| `getAgentDetail(pubkey)` | Get agent metadata (org, status, creation date) |
| `getAgentPolicy(pubkey)` | Check the agent's policy pack and jail status |
| `getPendingHeldActions(orgName, maxCount)` | List actions waiting for operator approval |
| `getHeldActionReviews(orgName, maxCount)` | List completed operator reviews |
| `getSafetyStats()` | Chain-wide safety statistics |

### Agent identity

Standalone helpers for keypair handling.

| Function | Use case |
|---|---|
| `generateKeypair()` | Generate a fresh secp256k1 keypair |
| `derivePublicKey(privkey)` | Derive the public key from a private key |
| `isValidPrivateKey(hex)` | Validate a private-key string |
| `loadAgent(privkey)` | Validate the key + return `{ pubkey, privkey }` |

## Configuration

Configuration is resolved with priority: **constructor arg > env var > config file** (`~/.config/atbash/config.json`).

```ts
import { Atbash } from "@atbash/sdk";
const atbash = Atbash.fromConfig();   // reads env + config file
```

| Config key | Env var |
|---|---|
| `agentKey` | `ATBASH_AGENT_KEY` |
| `orgName` | `ATBASH_ORG_NAME` |
| `judgeEndpoint` | `ATBASH_ENDPOINT` |
| `blockchainRid` | `ATBASH_BLOCKCHAIN_RID` |
| `provider` | `ATBASH_PROVIDER` |
| `providerModel` | `ATBASH_PROVIDER_MODEL` |

Persistent config helpers: `saveUserConfig(config)`, `loadUserConfig()`, `resolve(key, flagValue?)`, `getConfigPath()`.

## Error handling

The SDK throws standard `Error` objects. Known failure modes are enriched with a pointer to the dashboard page that fixes them:

```
API error 404: {"error":"Agent not registered..."}
  → Onboard the agent at https://atbash.ai/risk-engine/agents
```

| Error | Cause | Where to fix |
|---|---|---|
| `API error 404: Agent not registered` | Agent not onboarded | [atbash.ai/risk-engine/agents](https://atbash.ai/risk-engine/agents) |
| `API error 400: Agent has no policy` | No policy attached to agent | [atbash.ai/risk-engine/agents](https://atbash.ai/risk-engine/agents) |
| `Agent is jailed` | BLOCK verdict triggered auto-jail | [atbash.ai/risk-engine/agents](https://atbash.ai/risk-engine/agents) |
| `Verdicts are disabled` | Org has no active subscription | [atbash.ai/risk-engine/settings](https://atbash.ai/risk-engine/settings) |
| `API error 400: action is required` | Empty action string | Fix caller |

```ts
try {
  const result = await atbash.judgeAction(action, context);
} catch (err) {
  if (err.message.includes("Agent not registered")) {
    // Point the user at https://atbash.ai/risk-engine/agents to onboard.
  }
}
```

## Dashboard

Policy authoring, operator reviews, and agent management happen at [atbash.ai](https://atbash.ai/). The SDK is the programmatic interface; the dashboard is the operator interface.

## License

Proprietary — all rights reserved. See [LICENSE](https://atbash.ai/license).
