# Design Memo &mdash; JAMES as Agent-Callable Policy + Knowledge Backend (v1.0+)

> **Status**: design memo, not roadmap commitment.
> **Target cycle**: v1.0 (after first domain pilot + production maturity).
> **Owner**: maintainer.
> **Last updated**: v0.2.1 entry.

---

## 0. TL;DR

After v1.0, agent frameworks (OpenClaw, LangChain, LlamaIndex,
OpenAI Agents SDK, MCP-compatible clients, Anthropic Tool Use, etc.)
need a place to ground their reasoning in private documents AND a
place to ask "is the user allowed to do X?". JAMES is well-positioned
to be that backend.

This memo defines:

- the API surface JAMES exposes to external agents
- the trust model (agent identity + user context + capability tokens)
- the protocol choices (OpenAI-compatible HTTP + native MCP server)
- integration patterns for LangChain / LlamaIndex / Agents SDK / MCP
- how audit / trace / policy compose with the agent's own logs
- what JAMES deliberately does NOT do (run agents)

This positions JAMES as **"the Postgres for AI agents in cloud-rejecting
domains"** &mdash; boring, reliable, audit-friendly infrastructure rather
than a competing agent framework.

---

## 1. Motivation

Two forces are converging:

1. **Agent frameworks are eating product positioning.** OpenClaw's
   marketplace shows 162+ ready agents in months. LangChain has
   hundreds of skills. Anthropic Tool Use ships in production.
   Agents are where end-user attention is.

2. **Agents have no answer for policy + audit + private knowledge.**
   Every agent framework punts on RBAC, audit log, PII masking,
   role-aware retrieval. They expect the host application to provide
   it. In regulated domains (government, finance, healthcare, legal)
   this gap is the deal-breaker.

JAMES fills that gap. After v1.0, instead of competing with agents,
we expose JAMES as the layer agents call when they need to ground
in private docs OR ask "may the user do this?".

---

## 2. Goals (v1.0+)

- **G1.** Any agent framework that can call HTTP or speak MCP can
  use JAMES as its retrieval + policy + audit backend without
  coupling to JAMES internals.
- **G2.** Agent identity is a first-class concept distinct from
  user identity. Audit log answers *"which agent, acting on behalf
  of which user, retrieved what?"*.
- **G3.** Policy decisions are cacheable per `(role, action, resource)`
  to keep agent loop latency under 50 ms for the policy hot path.
- **G4.** External agents cannot escalate beyond their delegating
  user's role. Capability tokens encode the user's role at issuance
  time and are scoped to one action.
- **G5.** API SemVer is independent of internal SemVer. v1.0 API
  has a 12-month deprecation guarantee for any field removal.

## 3. Non-goals

- **N1.** JAMES does not execute agent actions. No code execution,
  no web fetch, no file writes invoked by external agents. Agents
  call JAMES to ASK; agents themselves DO.
- **N2.** No multi-agent orchestration. JAMES is the data and
  policy layer. Coordination is the framework's job.
- **N3.** No agent skill marketplace. The marketplace is plugin
  packs (domain ontologies + prompts), not agent definitions.
- **N4.** No agent identity provider. JAMES verifies agent identity
  via signed tokens issued by an external IdP or by JAMES's own
  admin, but does not run as an IdP for arbitrary external systems.
- **N5.** No agent-to-agent communication routing. JAMES is a backend,
  not a message bus.

---

## 4. Core API surface

Five primitives. Everything else composes from these.

### 4.1 `retrieve(query, role, context)` &rarr; Grounded

```python
class Grounded(TypedDict):
    chunks: list[Chunk]              # text + source path + score
    graph_paths: list[GraphPath]     # entity to relations to entity
    citations: list[Citation]        # canonical citation strings
    trace_id: str                    # links to /admin/trace/{id}
```

The agent passes the user's role + the agent's own identity. JAMES
runs the full retrieve &rarr; graph &rarr; policy &rarr; output filter pipeline
and returns grounded content the agent can put in its context.

### 4.2 `check_policy(role, action, resource)` &rarr; Decision

```python
class Decision(TypedDict):
    allowed: bool
    reason: str
    applied_rule: str
    cached_until: int | None         # unix timestamp; honor for caching
```

Cheap, pre-decision check the agent uses to avoid wasted LLM calls.
"Can role X do action Y on resource Z?" Answer in &lt; 50 ms.

### 4.3 `issue_capability(role, action, scope, ttl_seconds)` &rarr; Token

Short-lived, scoped capability token. Used when the agent will make
repeated calls for the same operation (e.g. iterating through search
results). Token is bound to `(agent_id, user_role, action, scope, expiry)`.

### 4.4 `emit(content, role, agent_id, trace_id)` &rarr; Emitted

```python
class Emitted(TypedDict):
    content: str                     # post PII-mask + role-filter
    redactions: list[Redaction]      # what was masked, by which rule
    audit_id: str
```

Output filter as a service. Agent generates content, calls `emit`
to mask PII / role-restricted info before showing the user.

### 4.5 `log_agent_action(agent_id, action, trace_id, fields)` &rarr; AuditId

Append-only audit log entry. Agent records what it did. Audit chain
becomes: agent reasoning + JAMES retrieve + JAMES emit, all linked
by trace_id.

---

## 5. Trust model

Three identities in every call:

- **Agent identity** &mdash; signed JWT issued at agent registration.
  Carries: `agent_id`, owner (user/org), `allowed_actions`,
  `allowed_scopes`.
- **User context** &mdash; the human the agent acts on behalf of.
  Carries: `user_id`, `role`, `sensitivity_clearance`.
- **Capability token** (optional, for hot loops) &mdash; short-lived,
  bound to specific action+scope.

Resolution at every call:

1. Verify agent JWT signature
2. Verify user role from agent's `acting_as` claim (signed by user
   delegation)
3. **Lower of** `agent.allowed_actions` and `user.role` determines
   the effective ABAC level
4. Audit log records all three

This prevents an agent from doing more than its delegating user can do.
An agent owned by an admin still cannot access secret data when acting
on behalf of an external user.

---

## 6. Protocol choices

Two front doors. Same backend.

### 6.1 OpenAI-compatible HTTP API (`/v1/...`)

For framework compatibility. Most agent frameworks (LangChain,
LlamaIndex, OpenAI Agents SDK, OpenClaw) speak OpenAI-shaped APIs
natively. Mapping:

- `POST /v1/chat/completions` &mdash; wraps `retrieve` + LLM call
- `POST /v1/retrieve` &mdash; JAMES extension (non-OpenAI)
- `POST /v1/policy/check` &mdash; JAMES extension
- `POST /v1/embeddings` &mdash; embedding service for ground-up indexing

OpenAI-compatible minimizes integration friction. Frameworks see JAMES
as "yet another OpenAI-compatible endpoint with retrieval extensions".

### 6.2 Native MCP server

Anthropic's Model Context Protocol is becoming the lingua franca for
tool/data servers (Claude Desktop, Anthropic API tool use, many emerging
frameworks). JAMES exposes itself as an MCP server with these tools:

- `james.retrieve(query, role)`
- `james.check_policy(role, action, resource)`
- `james.emit(content, role)`
- `james.list_packs()` &mdash; what domain packs are installed

MCP gives Claude Desktop, Cursor, and any MCP client direct access
without writing custom integration code.

### 6.3 Out of scope (for v1.0)

- gRPC &mdash; premature optimization; HTTP+MCP cover 99% of agents
- WebSocket / SSE for streaming retrieve &mdash; v1.1 if traffic justifies
- Custom JAMES SDK in non-Python languages &mdash; community contributes
  if demand emerges

---

## 7. Integration patterns (illustrative)

### 7.1 LangChain

```python
from langchain.retrievers import JAMESRetriever
from langchain.tools import JAMESPolicyTool

retriever = JAMESRetriever(
    base_url="http://localhost:8000",
    agent_token=os.environ["JAMES_AGENT_TOKEN"],
    user_role="manager",
)
agent = create_react_agent(
    llm=ChatAnthropic(),
    tools=[JAMESPolicyTool(...), retriever.as_tool()],
)
```

### 7.2 OpenAI Agents SDK

JAMES appears as a `function_tool` named `retrieve_grounded`. The
agent calls it like any other function; JAMES handles policy underneath.

### 7.3 MCP (Claude Desktop, Cursor, etc.)

User adds JAMES to their MCP servers list. Tools auto-appear in the
agent's toolbox. Zero integration code on the client side.

### 7.4 Custom HTTP

For bespoke agents:

```bash
curl -H "Authorization: Bearer $AGENT_TOKEN" \
     -H "X-User-Role: manager" \
     -d '{"query":"refund policy applicable?"}' \
     http://james/v1/retrieve
```

---

## 8. Layering with domain packs

Agents do not know which pack served them. The flow:

```
Agent --> JAMES API
           |
        Policy gate (Axis 4 PolicyEngine)
           |
        Pack router (loads packs/cafe or packs/legal based on workspace config)
           |
        Pack-specific ontology + prompts apply
           |
        Mother retrieval pipeline runs
           |
        Mother output filter
           |
Agent <-- Grounded response
```

This means a single `james-cafe` deployment can serve many agent
frameworks. The framework chooses the agent UX; JAMES provides the
data + policy.

---

## 9. Audit / observability composition

Trace_id chain:

1. Agent generates `agent_request_id` at user input
2. Calls JAMES with `agent_request_id` in header
3. JAMES generates internal `trace_id` and links to `agent_request_id`
4. Every JAMES stage log includes both ids
5. Agent's own logs reference `agent_request_id`
6. Reverse trace: from agent log &rarr; JAMES `/admin/trace/{trace_id}`

When something goes wrong:

- Agent log shows agent reasoning
- JAMES `/admin/trace/{trace_id}` shows what data was returned, what
  policy decisions were made
- Both are reproducible without re-running

---

## 10. Versioning + deprecation

API SemVer is independent of internal SemVer.

- `/v1/...` &mdash; stable; field removal requires 12-month deprecation
- `/v2/...` &mdash; breaking changes go here when needed
- Deprecation header on responses: `Sunset: Wed, 30 Nov 2027 23:59:59 GMT`
- SDK clients warn loudly when calling deprecated fields

This decouples internal refactoring from external agent stability.

---

## 11. Performance budget

| Operation | p50 target | p99 target |
|---|---|---|
| `check_policy` (cache hit) | &lt; 5 ms | &lt; 20 ms |
| `check_policy` (cache miss) | &lt; 50 ms | &lt; 200 ms |
| `retrieve` (small query, cached) | &lt; 200 ms | &lt; 800 ms |
| `retrieve` (full pipeline) | &lt; 2 s | &lt; 10 s |
| `emit` (PII filter only) | &lt; 10 ms | &lt; 50 ms |

Achieving these requires:

- LRU cache for policy decisions (Axis 4 PolicyEngine already plans this)
- Pre-warmed embedding cache
- Async I/O on Ollama calls
- Streaming for long generations

---

## 12. Failure modes

- **JAMES down** &rarr; agents must have a fallback ("data-unavailable"
  pathway in agent prompts). JAMES should not be a single point of
  failure for the agent.
- **Policy ambiguous** &rarr; JAMES fails closed (deny + log). Never
  default-allow.
- **Capability token expired** &rarr; 401 with clear message; agent
  re-issues.
- **Agent identity revoked** &rarr; 403; admin can revoke via
  `/admin/agents` endpoint without restarting JAMES.
- **Network partition** &rarr; read-only operations (retrieve, policy
  cache) work from local cache; write operations (audit log) buffer to
  disk and flush on reconnect.

---

## 13. What we deliberately do NOT build

- A JAMES-branded agent framework
- An agent skill marketplace
- A code execution sandbox accessible from external agents
- An agent identity provider for non-JAMES systems
- Web browsing as a tool exposed to agents
- File system write tools exposed to agents

These belong in the agent frameworks themselves. JAMES is the ground
truth, not the actor.

---

## 14. Phased delivery

This memo describes the v1.0 target. Path to get there:

| Phase | Work | Cycle |
|---|---|---|
| Prep | Axis 4 PolicyEngine extracted (issue #44) | v0.2 |
| Prep | trace_id end-to-end (issue #47) | v0.2 |
| Prep | Plugin API (`core/plugins/base.py`) | v0.3 |
| Prep | First domain pack pilot validated | v0.4 |
| GA | API surface (sect. 4) implemented | v1.0 |
| GA | OpenAI-compatible HTTP + MCP server | v1.0 |
| GA | Reference SDK in Python | v1.0 |
| GA | LangChain integration recipe | v1.0 |
| Post | LlamaIndex / OpenAI Agents SDK recipes | v1.1 |
| Post | Streaming retrieve | v1.1 |
| Post | gRPC if justified by traffic | v1.2+ |

---

## 15. Open questions

These are deliberately not resolved in this memo &mdash; they need real
data from v0.4 pilot + v1.0 readiness work.

- **Q1.** Should agent identity be JAMES-issued or BYO (bring your
  own JWT signed by external IdP)? Trade-off: simplicity vs. control.
- **Q2.** What happens when an agent retrieves data and then the
  underlying document is deleted / sensitivity-upgraded? Stale context
  in the agent's history is a real issue.
- **Q3.** Rate-limiting model: per-agent? per-user? per-(agent, user)?
- **Q4.** Should JAMES expose embedding generation as a service to
  agents, or is that scope creep?
- **Q5.** How do we prevent prompt-injected content (returned by
  `retrieve`) from poisoning the agent's downstream reasoning when
  the agent is outside JAMES's control?

Each will be revisited in the v1.0 cycle entry handover.

---

## 16. References

- `docs/PLATFORM_READINESS.md` Gate v1.0 &mdash; production-grade mother
- `docs/ARCHITECTURE.md` sect. 2 Non-goals (this memo expands on what
  JAMES does NOT do as an agent backend)
- `docs/handovers/v0.2.0-platform-track.md` Axis 4 PolicyEngine prep
- Anthropic MCP spec: https://modelcontextprotocol.io/
- OpenAI API spec (for compatibility surface)

---

## 17. 한국어 요약

v1.0 시점에 자메스를 **에이전트 프레임워크가 호출 가능한 정책·지식
백엔드**로 노출하는 설계입니다. 핵심 개념:

1. 자메스는 **에이전트가 아니다**. 에이전트는 OpenClaw·LangChain·
   MCP 클라이언트 등이 맡고, 자메스는 그들이 "검색·정책 체크·감사"
   를 위해 호출하는 백엔드 역할.
2. 5개 핵심 API: `retrieve`, `check_policy`, `issue_capability`,
   `emit`, `log_agent_action`.
3. 프로토콜: OpenAI 호환 HTTP + MCP 서버 (둘 다 v1.0에 제공).
4. 신뢰 모델: 에이전트 ID + 사용자 ID + capability 토큰 3중 확인.
   에이전트는 **위임받은 사용자보다 권한이 높을 수 없음**.
5. 도메인 팩과 자연 결합: 에이전트는 어느 팩이 답했는지 모름.
   workspace 설정에 따라 cafe·legal·government 팩이 응답.
6. 명시적 비-목표: 에이전트 자체 실행, 마켓플레이스, 코드 샌드박스
   외부 노출, 에이전트 간 통신 라우팅 &mdash; 모두 에이전트 프레임워크의
   책임.
7. v0.2/v0.3/v0.4 작업이 모두 이 v1.0 API의 토대가 됨 (특히
   Axis 4 PolicyEngine과 Axis 3 trace_id가 백본).

이 메모는 **로드맵 약속이 아니라 설계 메모**입니다. 실제 구현은
v0.4 파일럿 결과와 v1.0 사이클 진입 시점의 시장 신호에 따라 조정됩니다.
