Introduction
OAM — Object Agent Mapping — is the framework for giving agents, services, and automation structured and policy-aware access to data.
Where an ORM (Object Relational Mapping) maps application objects to relational rows, OAM maps agent intent to data operations. The framework controls how an agent discovers, accesses, and works with data — and enforces those rules consistently across languages and deployment patterns.
ROAM is the runtime that implements OAM. It provides identity-aware execution, policy enforcement, and agent-ready context across application and service boundaries.
Schema Modes
OAM defines three operating modes that determine how an agent interacts with data:
| Mode | Description | Access |
|---|---|---|
| Data-First | The agent discovers the database schema at runtime through introspection. No application model registration required. Best for exploring legacy or external databases. | Read-only |
| Code-First | Only tables explicitly registered by the application are accessible. The application controls validation and access rules. Best when the codebase owns the data. | Read-write |
| Hybrid | Registered models take precedence; unknown tables fall back to introspection. Provides coverage without sacrificing safety where code coverage ends. | Read-only |
Choose Data-First when agents need to explore data without committing to a code model. Choose Code-First when your application owns the data and must enforce validation rules. Use Hybrid when your codebase covers some tables but you still want introspection for the rest.
What This Book Covers
- Architecture explains how ROAM fits into application, service, and event-driven systems.
- Runtime Context explains how request metadata and runtime augmentation travel with execution.
- Contributing explains how to propose changes to the public runtime, SDKs, and documentation.
- SDK Guides help you choose the best starting point for Python and .NET integrations.
Where ROAM Fits
ROAM is designed for teams that want to:
- add policy-aware execution to application and service workflows
- carry stable identity and organization context through runtime operations
- integrate agent-driven or automation-driven behavior without rewriting existing systems
- standardize public integration contracts across multiple languages
Operating Patterns
ROAM typically appears in one of two patterns:
- Application-intercepted flows where ROAM validates and enriches requests as they move through an API or service boundary.
- Event-driven flows where ROAM observes or participates in runtime decisions driven by messages, RPC calls, or automation pipelines.
Quick Links
- roam-public for the public Rust core and shared runtime contract
- roam-python for Python integrations and automation workflows
- roam-dotnet for .NET services and typed enterprise integrations
Suggested Starting Path
- Start with Architecture Overview to understand the public runtime model.
- Read Runtime Context if you need request metadata and runtime-augmentation guidance.
- Choose your SDK: Python or .NET.
- Use API Reference when you are ready for package and protocol details.
Architecture Overview
ROAM is designed as a public runtime layer that sits close to execution boundaries. It helps products and services carry identity, policy, and agent-aware context through application logic without forcing teams to redesign the rest of their stack.
The Object Agent Mapping Model
OAM gives the architecture a stable contract for how agents interact with data. Instead of giving an agent direct or unrestricted database access, OAM sits between the agent and the data layer and mediates what the agent can see and do based on the active schema mode.
Schema mode is selected at agent registration time and governs the entire session:
- In Data-First mode, the runtime introspects the live database so the agent can discover and query data without a pre-defined application model. Access is read-only.
- In Code-First mode, only explicitly registered application models are accessible. The application controls validation and data access rules, enabling safe read-write operations.
- In Hybrid mode, registered models take precedence for known tables and the runtime falls back to introspection for everything else. Access is read-only where code coverage ends.
All three modes carry identity and runtime context through the execution path so agent queries stay aligned with organizational policy regardless of which mode is active.
Public Runtime At A Glance
The public ROAM surface is organized around three adoption layers:
- Core runtime for shared execution, reflection, and protocol behavior.
- Language SDKs for integrating ROAM into Python and .NET applications.
- Shared protocol definitions for teams that need language-neutral contracts or generated bindings.
Public Building Blocks
Runtime Model
The runtime model gives ROAM a consistent way to:
- interpret structured requests and tool-facing operations
- apply identity and organization context to execution
- attach runtime augmentation metadata before validation and execution
- emit audit-safe events and observable outcomes
SDK Layer
The Python and .NET SDKs package that runtime model into language-specific integration surfaces. They are the fastest path for teams that want to add ROAM to existing products, services, and automation workflows.
Shared Contract
When teams need multi-language interoperability, generated clients, or direct protocol-level integration, the shared protobuf and gRPC contract provides the stable public boundary.
Where ROAM Fits In The Stack
ROAM usually appears in one of these roles:
- Request-path integration where a service or API validates and enriches execution context before work continues.
- Runtime coordination where a client or middleware layer passes identity, tool, and organization context into downstream execution.
- Event-driven integration where ROAM participates in decisions triggered by messages, jobs, or automation pipelines.
Adoption Paths
Start With An SDK
Use an SDK when you want to move quickly inside an application stack. This is the best fit for:
- service teams integrating ROAM into existing APIs
- platform teams standardizing runtime context across applications
- automation teams building product or operations workflows
Start With The Shared Contract
Use the protocol definitions when you want to:
- generate your own client bindings
- align multiple services around one public contract
- integrate from a language or platform that does not yet have a first-party SDK
Operating Modes
ROAM supports both user-driven and event-driven execution patterns.
Application-Driven Mode
In application-driven flows, a user or upstream service initiates the request. ROAM enriches or validates that request as it moves through an application or API boundary.
Event-Driven Mode
In event-driven flows, ROAM participates when a message, RPC call, or background job creates a decision point that needs shared runtime context or policy-aware behavior.
Middleware Architecture
ROAM middleware is the integration layer that lets products apply shared runtime context, identity-aware execution, and policy decisions close to the point where work actually happens.
Runtime Flow At The Boundary
At a high level, ROAM middleware does three things for every participating request:
- establish who or what is acting
- attach the runtime context needed to make a safe decision
- pass only validated execution downstream
The diagram below shows the logical shape of that flow.
Request Flow Diagram
This diagram shows the abstract pipeline a request moves through before execution continues.
sequenceDiagram
participant Client as Client Application
participant API as Product API / Service Boundary
box "ROAM Middleware Layer" #f9f9f9
participant Identity as Identity Context
participant Runtime as Runtime Interceptor
participant Policy as Policy Review
end
participant Data as Downstream Service / Data Layer
Note over Client, API: Request enters a ROAM-enabled boundary
Client->>API: 1. Submit request
rect rgb(35, 35, 35)
Note over API, Identity: Layer 1: Identity and request context
API->>Identity: 2. Resolve identity and context
Identity->>Identity: Match trusted identity inputs
alt Identity Invalid
Identity-->>API: 401 Unauthorized
API-->>Client: Authentication error
else Identity Valid
Identity->>Runtime: 3. Attach runtime context
end
end
rect rgb(40, 35, 35)
Note over Runtime, Policy: Layer 2: Validation and policy review
Runtime->>Runtime: Interpret request intent
Runtime->>Policy: 4. Evaluate request
Policy->>Policy: Apply execution rules
alt Request Rejected
Policy-->>Runtime: Block execution
Runtime-->>API: 403 Forbidden
API-->>Client: Request rejected
else Request Approved
Policy-->>Runtime: 5. Continue
end
end
rect rgb(35, 40, 35)
Note over Runtime, Data: Layer 3: Downstream execution
Runtime->>Data: 6. Execute downstream work
Data-->>Runtime: 7. Return result
end
Runtime-->>API: 8. Format response
API-->>Client: 9. Final result
What This Layer Adds
- Identity-aware context so requests carry the organization, user, or tool information needed for safe execution.
- Interception at the right boundary so ROAM can enrich or validate intent before it reaches core business logic.
- Policy-aware execution so only approved operations continue into downstream systems.
- Minimal disruption to existing systems so teams can integrate ROAM without redesigning their application architecture.
Integration Models
ROAM is designed to be protocol-agnostic and to sit as close as possible to the moment where intent becomes execution.
Model 1: Embedded Request Integration
This model fits products that already have an API layer and want ROAM to participate in request handling without changing the rest of the application stack.
Common fit:
- existing APIs and service boundaries
- application teams adding runtime context and policy checks
- products that want ROAM close to synchronous request handling
sequenceDiagram
participant User as End User (UI)
participant API as Product API
participant OAM as ROAM Middleware
participant Runtime as ROAM Runtime
participant DB as Data Layer
Note over User: 1. User action begins in the product
User->>API: 2. API Request
rect rgb(35, 35, 35)
Note over API, OAM: Embedded request boundary
API->>OAM: Intercept and enrich request
OAM->>OAM: Resolve identity and runtime context
par Runtime Coordination
OAM--)Runtime: Emit runtime event
and Request Validation
OAM->>OAM: Evaluate request policy
end
alt Valid
OAM->>API: Continue request
API->>DB: Execute application work
DB-->>API: Result
API-->>User: Response
else Rejected
OAM-->>User: 403 Rejected Request
end
end
Model 2: Proxy Or Sidecar Boundary
This model fits systems that do not expose a clean application middleware layer but still need a controlled integration boundary.
Common fit:
- legacy applications
- direct data-access clients
- environments that need interception outside the primary application codebase
sequenceDiagram
participant User as Existing Application
participant Proxy as ROAM Proxy / Sidecar
participant Runtime as ROAM Runtime
participant DB as Data Layer
participant Identity as Identity Source
Note over User: 1. Existing system issues a request
User->>Proxy: 2. Forward request to boundary layer
rect rgb(40, 35, 35)
Note over Proxy: Boundary interception
Proxy->>Identity: Resolve permissions and context
Proxy--)Runtime: Emit runtime event
Proxy->>Proxy: Evaluate request rules
alt Approved
Proxy->>DB: Execute downstream request
DB-->>Proxy: Rows
Proxy-->>User: Result
else Blocked
Proxy-->>User: Rejected Request
end
end
Model 3: Hybrid Runtime Placement
This model fits teams that need local execution boundaries but still want shared governance, visibility, or centralized coordination patterns.
Common fit:
- high-compliance deployments
- organizations with mixed hosted and self-managed infrastructure
- teams that need execution inside their own perimeter
Model 4: Fully Self-Hosted Runtime
This model fits teams that want full control of runtime placement and operational ownership.
Common fit:
- air-gapped or highly restricted environments
- self-managed platform teams
- development and experimentation workflows built entirely on the public stack
sequenceDiagram
participant Source as Product Event Source
participant OAM as Local ROAM Runtime
participant Logic as Business Logic
participant DB as System of Record
Source->>OAM: Event / RPC Call
rect rgb(35, 35, 45)
Note over OAM: Local execution boundary
OAM->>OAM: Apply local validation and context
OAM->>Logic: Invoke Handler
end
Logic->>DB: Update State
DB-->>Logic: Success
Logic-->>OAM: Confirmation
OAM-->>Source: Result
Choosing The Right Boundary
Pick the model that keeps ROAM closest to the boundary where your system already makes trust and execution decisions. For most teams, that means starting with an SDK or embedded middleware pattern and expanding only when deployment constraints require it.
Runtime Context
Runtime context is how ROAM keeps execution grounded in the real application state that surrounds a request. It gives clients and services a public way to attach stable metadata before validation and execution begin.
Why Runtime Context Matters
Runtime context helps ROAM answer practical questions such as:
- which tool or product surface initiated this request
- which user or organization the request belongs to
- which domain tags or table scopes matter for this execution
- which runtime augmentation should be applied before downstream work continues
Without that context, a request may still be valid at the protocol level but incomplete from a product and governance perspective.
Runtime Augmentation
Runtime augmentation is the public mechanism for selecting additional execution context before a request is evaluated.
Clients can use:
x-roam-runtime-augmentation-idwhen they already know the specific augmentation identifierx-roam-runtime-augmentation-keywhen they want to reference a stable application-facing key
Additional headers help ROAM match the right augmentation and preserve the meaning of the request:
x-roam-tool-namex-roam-tool-intentx-roam-user-idx-roam-organization-idx-roam-domain-tagsx-roam-table-names
What Clients Should Send
Send the smallest stable set of metadata that explains why the request exists and which business boundary it belongs to.
Good examples include:
- the name of the calling product surface or tool
- the user or service identity associated with the request
- the tenant or organization boundary
- domain tags that explain business meaning
- table or resource hints when the execution path depends on them
What ROAM Emits
ROAM emits resolved augmentation identity into normal query and runtime events so downstream systems can observe which public context was selected.
Sensitive rendered content is intentionally separated from generic event metadata and reserved for dedicated audit handling.
Integration Guidance
Use runtime context when you want ROAM behavior to stay aligned with application intent rather than just raw transport details.
Typical uses include:
- attaching product identity in a multi-surface application
- carrying organization context through service-to-service calls
- selecting augmentation rules for automation or assistant workflows
- keeping audit and observability signals consistent across clients
Identity And BYOI
ROAM follows a Bring Your Own Identity approach so teams can integrate with the identity systems they already trust instead of recreating users, roles, and organization structure from scratch.
What BYOI Looks Like In Practice
With BYOI, ROAM aligns runtime behavior with your existing identity model by mapping external identity information into the public execution context.
That usually means carrying forward:
- organization or tenant boundaries
- user and service identity
- role or permission context
- capability or scope information that affects execution decisions
Why This Matters
Identity-aware execution helps teams:
- keep ROAM aligned with existing access-control boundaries
- preserve organizational context across application and service calls
- reduce drift between product identity and runtime behavior
- support agent and automation workflows without inventing a parallel permission system
Common Identity Sources
ROAM is well suited to identity models that originate from systems such as:
- enterprise directory providers
- source-control and collaboration platforms
- service-owned role and entitlement systems
- data-layer roles or scope definitions
The exact integration path can vary, but the goal stays the same: keep runtime decisions grounded in the identity model your organization already operates.
Identity In The Execution Path
Identity becomes most useful when it arrives with the request itself. In practice, that means ROAM can use identity context to:
- interpret which organization or tenant owns the request
- understand which actor initiated the work
- choose the right runtime augmentation or policy path
- emit more meaningful, audit-safe runtime events
Integration Guidance
The best BYOI integrations keep identity signals stable, explicit, and close to the request boundary.
Start by identifying:
- which system is the source of truth for identity
- which parts of that identity must influence runtime decisions
- which fields need to travel through the public ROAM headers or protocol surface
From there, use ROAM to preserve that context consistently across clients, services, and execution paths.
Contribution Workflow
ROAM accepts contributions across the public runtime, SDKs, and documentation. The goal of the workflow is simple: keep the public contract stable, keep changes reviewable, and make it clear where each kind of contribution belongs.
Choose The Right Repository
Start in the repository that owns the surface you want to improve.
- Use
roam-publicfor shared runtime behavior, public contract changes, and core Rust functionality. - Use
roam-pythonfor Python-specific helpers, bindings, packaging, and docs. - Use
roam-dotnetfor .NET-specific helpers, bindings, packaging, and docs.
Contribution Flow
- Fork the repository that matches your change.
- Create a small, clearly named branch.
- Add or update tests with the change.
- Update documentation when the public workflow or contract changes.
- Open a pull request against
main. - Address review feedback and keep the branch current until merge.
Branch And PR Expectations
- Keep each change focused enough to review in one pass.
- Prefer small pull requests over large mixed-scope changes.
- If a unit test needs excessive mocking, simplify the production code before adding more scaffolding.
- If a test is called
integration, it should talk to a real started runtime over the network.
Local Validation
Enable the repo-managed hooks after cloning when they are available:
make hooks-install
The local pre-commit path is intended to catch quality and test failures before you open a pull request.
External Contributor Setup
Step 1: Fork And Clone
Example for roam-public:
git clone https://github.com/<your-username>/roam-public.git
cd roam-public
git remote add upstream https://github.com/oamrs/roam-public.git
Step 2: Create A Branch
Use a descriptive branch name that matches the change you are making.
git checkout -b improve-runtime-context-docs
Step 3: Make The Change
Guidelines:
- write tests alongside behavior changes
- prefer repo Make targets where they exist
- keep unit tests deterministic and in-process
- keep integration tests runtime-backed and network-bound
- update docs when the public contract or contribution workflow changes
Step 4: Open A Pull Request
Push your branch and open a PR against upstream/main:
git push origin improve-runtime-context-docs
Include:
- a short description of the change
- the problem being solved
- how you validated the change
- any public contract impact or compatibility notes
Review Standards
ROAM reviews focus on a few practical questions:
- does the change belong in this repository
- does the implementation stay within the intended public boundary
- do the tests match the behavior being claimed
- does the documentation still describe the public surface accurately
Common Paths
Fixing A Core Runtime Issue
Start with roam-public if the change affects shared runtime behavior, protocol shape, or public Rust functionality.
Improving A Python Integration
Start with roam-python if the change is specific to the Python developer experience, helper layer, or packaging surface.
Improving A .NET Integration
Start with roam-dotnet if the change is specific to the .NET developer experience, helper layer, or packaging surface.
Release Expectations
Pull requests validate changes. Releases publish them.
If you need publication timing or release behavior details, continue with Testing and Release Policy.
Testing and Release Policy
ROAM treats testing and release discipline as part of the public contract. The goal is not just to ship code that works, but to ship public surfaces that are validated, predictable, and safe to adopt.
Test Layers
Unit Tests
Unit tests should stay fast, deterministic, and in-process.
Expectations:
- no live RPC or HTTP calls
- no containers
- minimal mocking only
If a unit test needs a large mock hierarchy, treat that as a signal to simplify the production code.
Integration Tests
Integration tests should validate real boundaries.
Expectations:
- real network requests
- a runtime that actually starts
- real dependencies where the boundary matters
- no shortcut local clients standing in for protocol behavior
End-To-End Tests
End-to-end tests validate a deployed environment from the outside. They are the right fit for rollout, wiring, secret, and networking concerns when that environment exists.
CI Expectations
Pull requests to main should pass the quality profile relevant to the repository being changed. That can include:
- linting and formatting
- unit and integration tests
- build validation
- documentation builds
- coverage or maintainability gates where they add real signal
- dependency and security checks
SDK-specific maintainability gates are intentionally selective. They should exist where a codebase contains enough handwritten logic to justify them, not just because a language binding exists.
Local Validation
When available, enable the repo-managed hooks locally:
make hooks-install
The local hook path is intended to catch common failures before you open a pull request. It complements CI, but does not replace it.
Release Discipline
Validation and publication are separate steps.
The expected release path is:
- merge reviewed code to
main - allow validation to complete on the merged revision
- create the appropriate release tag when publication is intended
Current public release patterns include:
public-v*for public subtree publicationsdk-python-v*for Python SDK publicationsdk-<language>-v*as the general form for future SDK release workflows
Why This Separation Exists
Separating merge validation from publication keeps the public ROAM surface more predictable for adopters.
It ensures that:
- every published artifact passed review first
- release timing is deliberate rather than accidental
- public packages and docs stay aligned with validated source
- teams can reason about adoption risk more clearly
API Reference
Use this page to choose the fastest way to integrate ROAM into your product. Whether you are embedding ROAM into an application, automating workflows, or standardizing service-to-service communication, the references below point to the public surfaces intended for real adoption.
Client SDKs
Choose the SDK that best matches your application stack.
Build Python applications and automation flows that integrate ROAM with a lightweight, script-friendly client surface.
Integrate ROAM into .NET services and enterprise applications with a familiar typed client experience.
Use the core Rust crate when you want maximum control, native performance, or direct access to the public runtime model.
Shared Contract
When you need a language-neutral integration surface, start with the protocol definitions.
Protobuf Definitions
Review the public gRPC contract, message shapes, and service definitions that keep multi-language integrations aligned.
HTTP REST API
The Rocket HTTP backend exposes a live, interactive API reference via Swagger UI. Use it to explore endpoints, inspect request/response schemas, and try calls directly from the browser.
Browse all route schemas, try requests live, and inspect request/response bodies.
Requires the backend to be running (make http-start).
OpenAPI JSON: http://localhost:8000/api/openapi.json
Suggested Starting Points
- Building application logic in Python: start with the Python SDK.
- Shipping a service or platform integration on .NET: start with the .NET SDK.
- Building custom runtimes or native integrations: start with the Rust client crate.
- Aligning multiple clients or generating your own bindings: start with the protobuf definitions.
- Exploring or testing HTTP endpoints interactively: start with the Swagger UI.
Python SDK Guide
Use the roam-python package when you want to integrate ROAM into Python applications, automation workflows, and service-side tooling without giving up a script-friendly developer experience.
Why Choose The Python SDK
- Build Python services and internal tools that need direct access to ROAM capabilities.
- Add ROAM-backed workflow automation to notebooks, jobs, and lightweight application code.
- Move quickly with a familiar Python surface while staying aligned with the public ROAM contract.
Installation
pip install roam-python
What You Get
The Python SDK gives you:
- A Python-first client surface for integrating ROAM into application and automation code.
- Typed bindings over the public runtime model so Python code stays aligned with the supported ROAM contract.
- Utility helpers and examples that make it easier to adopt ROAM in real product and workflow scenarios.
Quick Start
from roam.mirror import ReflectionEngine
from roam.executor import GrpcServer
# Initialize reflection
engine = ReflectionEngine()
# Start server
server = GrpcServer()
server.run()
This is the fastest path when you want to stand up a Python-based integration, validate connectivity, and start building application logic around ROAM.
Runtime Augmentation
ROAM runtime calls can carry runtime-augmentation selection metadata so your application can attach stable request context before validation or execution.
Use the public runtime headers when you need ROAM behavior to reflect product context such as the calling tool, organization, or domain.
The key runtime headers are:
x-roam-runtime-augmentation-idto reference a specific augmentation identifierx-roam-runtime-augmentation-keyto reference a stable augmentation keyx-roam-tool-name,x-roam-tool-intent,x-roam-user-id,x-roam-organization-id,x-roam-domain-tags, andx-roam-table-namesto provide matching context
ROAM emits resolved augmentation identity into normal query events, while sensitive rendered content remains reserved for dedicated audit handling.
Suggested Starting Points
- Building automation, internal tools, or orchestration logic in Python: start here.
- Prototyping a ROAM integration before standardizing it across services: start here.
- Passing runtime context from application code into ROAM execution paths: start with the runtime-augmentation headers above.
Contributing
For Rust Core Changes
If you need to change the shared public runtime or core ROAM behavior:
- File an issue in roam-public
- Submit a PR to roam-public (see Contribution Workflow)
- Once merged and exported, the change flows to roam-python automatically
For Python Layer Improvements
To improve the Python experience, add helpers, or expand documentation:
- Fork roam-python
- Create a feature branch
- Make changes in
roam/(Python layer only) - Submit PR to roam-python/main
- We’ll review and merge
Example:
# Add a utility function
# roam/utils/config.py
def load_config_from_file(path: str) -> dict:
"""Load ROAM configuration from YAML file."""
...
API Reference
See the full API docs for the Python package surface, method signatures, and integration details.
.NET SDK Guide
Use the roam-dotnet package when you want to integrate ROAM into .NET services, enterprise applications, and platform components with a typed client experience that fits naturally into the broader .NET ecosystem.
Why Choose The .NET SDK
- Integrate ROAM into ASP.NET, worker services, and internal platform components.
- Build strongly typed service-to-service integrations on a familiar .NET foundation.
- Adopt ROAM in production applications without dropping to lower-level protocol work unless you need it.
Installation
dotnet add package Roam.Dotnet
Or via NuGet:
Install-Package Roam.Dotnet
What You Get
The .NET SDK gives you:
- A typed .NET integration surface for embedding ROAM into application and platform code.
- Interop over the public runtime model so .NET services stay aligned with the supported ROAM contract.
- Utilities and examples that help teams wire ROAM into real service and enterprise deployment patterns.
Quick Start
using Roam;
var engine = new ReflectionEngine();
var server = new GrpcServer();
await server.RunAsync();
This is the fastest way to stand up a .NET integration, validate the client path, and start wiring ROAM into a service or application workflow.
Runtime Augmentation
ROAM runtime calls can carry runtime-augmentation selection metadata so your .NET application can attach stable business and request context before validation or execution.
Use the public runtime headers when you need ROAM behavior to reflect application identity, tool intent, tenant boundaries, or domain-specific routing context.
The key runtime headers are:
x-roam-runtime-augmentation-idto reference a specific augmentation identifierx-roam-runtime-augmentation-keyto reference a stable augmentation keyx-roam-tool-name,x-roam-tool-intent,x-roam-user-id,x-roam-organization-id,x-roam-domain-tags, andx-roam-table-namesto provide matching context
ROAM emits resolved augmentation identity into normal query events, while sensitive rendered content remains reserved for dedicated audit handling.
Suggested Starting Points
- Shipping a typed platform or product integration on .NET: start here.
- Embedding ROAM into an ASP.NET or worker-service architecture: start here.
- Passing application context into ROAM execution paths: start with the runtime-augmentation headers above.
Contributing
For Rust Core Changes
If you need to change the shared public runtime or core ROAM behavior:
- File an issue in roam-public
- Submit a PR to roam-public (see Contribution Workflow)
- Once merged and exported, the change flows to roam-dotnet automatically
For .NET Layer Improvements
To improve the .NET developer experience, add helpers, or expand documentation:
- Fork roam-dotnet
- Create a feature branch
- Make changes in
Roam/(.NET layer only) - Submit PR to roam-dotnet/main
- We’ll review and merge
Example:
// Add a utility class
// Roam/Config/ConfigLoader.cs
public static class ConfigLoader
{
public static RoamConfig LoadFromFile(string path)
{
// Load configuration
}
}
API Reference
See the full API docs for the .NET package surface, method signatures, and integration details.
LlmSchema Derive Macro
The LlmSchema derive macro — provided by the oam-schema crate — generates a JSON Schema
description of any Rust struct whose fields are annotated with standard Serde attributes.
This schema is used at runtime to build context-aware prompts and to expose entity structure
to LLM tool-calls, gRPC clients, and the Python SDK.
How it works
#[derive(LlmSchema)] delegates to schemars::schema_for!() under
the hood and exposes a single method:
#![allow(unused)]
fn main() {
pub fn llm_schema() -> schemars::schema::RootSchema
}
The returned RootSchema is fully JSON-serialisable and can be embedded directly in prompts,
returned over gRPC, or published to the OpenAPI spec.
SeaORM integration (Rust)
SeaORM entity models are the primary target for LlmSchema. Add both LlmSchema and
JsonSchema to your DeriveEntityModel derive list:
#![allow(unused)]
fn main() {
use roam_schema::LlmSchema;
use schemars::JsonSchema;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize, LlmSchema, JsonSchema)]
#[sea_orm(table_name = "organizations")]
pub struct Model {
#[sea_orm(primary_key, auto_increment = false)]
pub id: Uuid,
pub name: String,
pub slug: String,
pub description: String,
pub owner_id: String,
}
}
With this in place, the schema is available at runtime without reflection:
#![allow(unused)]
fn main() {
let schema = organization::Model::llm_schema();
let schema_json = serde_json::to_string_pretty(&schema).unwrap();
}
Registering with a prompt hook
Pass the JSON schema to a PromptHookSchemaContext when resolving a prompt:
#![allow(unused)]
fn main() {
let schema_json = serde_json::to_string(&organization::Model::llm_schema()).unwrap();
let request = PromptHookResolveRequest {
schema_context: PromptHookSchemaContext {
database_id: Some("prod-db".to_string()),
table_names: vec!["organizations".to_string()],
domain_tags: vec!["identity".to_string()],
},
..Default::default()
};
}
The matching rules in your prompt hook YAML can reference table_names and domain_tags:
schema:
table_names: ["organizations"]
domain_tags: ["identity"]
SQLAlchemy integration (Python SDK)
The Python SDK exposes entity schemas through the RoamClient.get_schema() gRPC call.
You do not need to replicate SeaORM models in Python — the schema travels over the wire.
Installation
pip install roam-sdk
# or with uv
uv add roam-sdk
Fetching a schema
from roam_sdk import RoamClient
client = RoamClient(host="localhost", port=50051)
# Retrieve the JSON Schema for a specific entity table
schema = client.get_schema(table_name="organizations")
print(schema)
# → {"$schema": "http://json-schema.org/draft-07/schema#", "title": "Model", ...}
Using the schema with SQLAlchemy
The returned dict is a standard JSON Schema object. Pass it to your ORM model for dynamic validation or prompt-context injection:
import json
from sqlalchemy import create_engine, text
from roam_sdk import RoamClient
client = RoamClient(host="localhost", port=50051)
schema = client.get_schema(table_name="organizations")
# Validate a row dict against the schema (e.g. using jsonschema)
import jsonschema
jsonschema.validate(instance=row_dict, schema=schema)
# Or embed the schema directly in an LLM prompt
prompt_context = json.dumps(schema, indent=2)
Injecting schema into a prompt hook
from roam_sdk import RoamClient, PromptHookResolveRequest, SchemaContext
client = RoamClient(host="localhost", port=50051)
request = PromptHookResolveRequest(
schema_context=SchemaContext(
database_id="prod-db",
table_names=["organizations"],
domain_tags=["identity"],
)
)
resolution = client.resolve_prompt_hook(request)
print(resolution.rendered_prompt)
Field-level annotations
All standard Serde rename / skip attributes are respected by schemars:
#![allow(unused)]
fn main() {
#[derive(LlmSchema, JsonSchema, Serialize, Deserialize)]
pub struct Model {
pub id: Uuid,
/// Human-readable display name
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(rename = "ownerId")]
pub owner_id: String,
}
}
The generated schema will include the description from Rust doc-comments, honour rename,
and mark description as non-required because it is Option<…>.
Supported crates
| Crate | JsonSchema support |
|---|---|
serde_json::Value | built-in |
uuid::Uuid | via schemars uuid feature |
chrono::DateTime | via schemars chrono feature |
std::collections::BTreeMap | built-in |
Enable optional features in Cargo.toml:
schemars = { version = "0.8", features = ["derive", "uuid", "chrono"] }
API reference
The live HTTP API exposes all route schemas via Swagger UI. When the backend is running:
- Swagger UI: http://localhost:8000/api/swagger
- OpenAPI JSON: http://localhost:8000/api/openapi.json