System Bundles & Atoms¶
JarvisCore's integration model is built around two related ideas: atoms and system bundles.
An atom is a single, versioned, self-contained Python function that performs one action against one external system — send a Slack message, create a GitHub issue, read a Google Sheet row. It has a fixed signature, it owns its HTTP transport, and it never holds state.
A system bundle is a generated Python class that groups all atoms for a given system together — SlackCapabilities, GitHubCapabilities, StripeCapabilities — making them available to agent code and the code sandbox as a typed, injectable unit.
[!NOTE] Coming from MCP? System bundles are JarvisCore's native alternative to MCP tool servers. They are simpler (plain Python functions, no server process), tighter to the agent runtime, and carry an execution history that drives automatic promotion to production-ready status. See the MCP comparison below.
The Atom¶
Every atom is a standalone Python function that follows a strict contract:
def slack_send_message(auth_info: dict, channel: str, text: str, thread_ts: str = None) -> dict:
import requests
_base = "https://slack.com/api"
_h = {"Authorization": f"Bearer {auth_info.get('access_token', '')}", "Content-Type": "application/json"}
def _post(p, data=None):
r = requests.post(f"{_base}{p}", headers=_h, json=data, timeout=30)
r.raise_for_status()
return r.json()
payload = {"channel": channel, "text": text}
if thread_ts:
payload["thread_ts"] = thread_ts
resp = _post("/chat.postMessage", data=payload)
if not resp.get("ok"):
raise RuntimeError(resp.get("error", "Slack API error"))
return {"ts": resp["ts"], "channel": resp["channel"], "text": text}
The atom contract:
| Property | Rule |
|---|---|
| First parameter | Always auth_info: dict — populated by Nexus at call time |
| Return type | Always dict — structured, never raw HTTP response |
| Transport | Self-contained — imports requests internally |
| State | Stateless — no class, no instance, no side effects beyond the API call |
| Error handling | Raises on failure — the sandbox catches and reports |
Atoms intentionally embed their own import requests rather than relying on a shared HTTP client. This makes them independently executable in the code sandbox and portable across contexts.
The System Bundle¶
A system bundle is a generated {System}Capabilities class assembled from all atoms registered for a given system. The FunctionRegistry.create_system_bundle() method produces it:
# Generated by FunctionRegistry.create_system_bundle("slack")
class SlackCapabilities:
"""Capabilities for the Slack system.
Available functions:
- slack_send_message(auth_info, channel, text, thread_ts)
- slack_list_channels(auth_info)
- slack_get_channel_history(auth_info, channel_id, limit)
- slack_create_channel(auth_info, name, is_private)
- slack_invite_user(auth_info, channel_id, user_id)
- slack_add_reaction(auth_info, channel, timestamp, name)
"""
@staticmethod
def slack_send_message(auth_info, channel, text, thread_ts=None):
# ... atom code injected here
The bundle class is then prepended to any code the CoderSubAgent executes in the sandbox. This means agent-generated code can reference SlackCapabilities.slack_send_message(...) directly, with the atom implementation guaranteed to be available.
The Function Registry¶
Atoms are stored and tracked in the FunctionRegistry. The registry is a local filesystem store with an optional Redis cognitive projection for cross-agent discovery.
logs/function_registry/
├── metadata/
│ ├── slack_send_message.json ← execution stats, stage, SHA256
│ └── github_create_issue.json
├── atoms/
│ ├── slack/
│ │ ├── slack_send_message_v1.py
│ │ └── slack_send_message_v2.py ← atoms are immutable and versioned
│ └── github/
│ └── github_create_issue_v1.py
└── bundles/
├── slack_bundle.py
└── github_bundle.py
Every atom is immutable and versioned. When an atom is updated (by CoderSubAgent or by seeding), a new _v2.py is written rather than overwriting _v1.py. The SHA-256 hash of the function source is stored in metadata and verified on load.
Graduation¶
Every atom has a stage:
| Stage | Threshold | Meaning |
|---|---|---|
candidate |
Newly registered | Generated or seeded but not yet executed in production |
verified |
1 successful execution | Has run successfully at least once |
golden |
5 successful executions | Production-tested; preferred by CoderSubAgent on registry lookups |
Stage advances automatically when update_execution_stats(success=True) is called after a successful sandbox run. When CoderSubAgent searches the registry for an existing function, golden atoms score higher than verified, which score higher than candidates.
JIT: Just-In-Time Compilation¶
The registry's most powerful capability is JIT — agent code generation for systems and actions that don't yet have a pre-built atom.
When a task requires calling an external system and no matching atom exists in the registry, CoderSubAgent follows this fallback ladder:
1. check_registry(task)
└── Found a golden/verified atom? → reuse it, skip to execute
2. write_code(task)
└── CoderSubAgent writes a new atom from its training knowledge
└── ValidationLayer checks syntax and structure
└── Atom stored as "candidate" in registry
3. execute_code(function_name)
└── SandboxExecutor runs the atom in an isolated environment
└── On success → stage promoted to "verified"
└── On failure → diagnose, rewrite, retry (max 2 attempts)
└── On persistent failure → delegate_research as last resort
4. register_success(function_name)
└── Execution stats updated
└── Atom available for reuse in future calls
This means the first time your agent needs to call, say, quickbooks_create_invoice, it writes and tests that function live. Every subsequent call skips straight to step 1 — the atom is already in the registry.
Naming convention: All atoms registered by CoderSubAgent follow {system}_{action} — e.g. stripe_create_payment_intent, notion_create_page, github_list_open_prs.
The 19 Pre-Seeded Systems¶
JarvisCore ships with 77 pre-built atoms across 19 system bundles, seeded at startup via seed_registry.py. Pre-seeded atoms start as candidate and promote to verified after first successful use in your environment.
Communication¶
| System | Atoms | Auth |
|---|---|---|
| Slack | send_message, list_channels, get_history, create_channel, invite_user, add_reaction | OAuth2 |
| Gmail | send_email, list_messages, get_message, create_draft | OAuth2 |
| SendGrid | send_email, get_stats | API key |
| Brevo | send_email, get_contacts, create_contact | API key |
| Mailchimp | add_subscriber, get_lists, send_campaign | API key |
Development¶
| System | Atoms | Auth |
|---|---|---|
| GitHub | create_issue, list_issues, create_pr, merge_pr, get_file, update_file, add_comment, list_repos | OAuth2 |
| Linear | create_issue, get_issue, list_issues, update_issue, search_issues | OAuth2 |
| Jira | create_issue, get_issue, update_issue | Basic auth |
Productivity¶
| System | Atoms | Auth |
|---|---|---|
| Notion | create_page, get_page, list_databases, query_database, update_page, search | OAuth2 |
| Google Drive | list_files, upload_file, download_file, share_file | OAuth2 |
| Google Sheets | read_range, write_range, append_rows, get_spreadsheet | OAuth2 |
| Google Calendar | list_events, create_event, delete_event | OAuth2 |
| Airtable | list_records, create_record, update_record, delete_record, get_record, search_records, get_schema, batch_create | API key |
CRM & Sales¶
| System | Atoms | Auth |
|---|---|---|
| HubSpot | create_contact, get_contact, create_deal, update_deal, list_contacts | OAuth2 |
| Salesforce | create_record, query_records, update_record, get_record | OAuth2 |
| Apollo | search_people, enrich_person, get_account | API key |
Finance¶
| System | Atoms | Auth |
|---|---|---|
| Stripe | create_payment_intent, list_customers, create_customer, get_balance | API key |
| QuickBooks | get_company_info, list_invoices, create_invoice, get_reports | OAuth2 |
Search¶
| System | Atoms | Auth |
|---|---|---|
| Serper | search, news_search | API key |
This Is Not MCP¶
The Model Context Protocol (MCP) by Anthropic is a standard for connecting LLM applications to external tools via a client-server protocol. It's a well-designed standard — MCP servers run as separate processes, expose tools via a JSON-RPC-like protocol, and clients discover and call them at runtime.
JarvisCore's atom model takes a different approach, and it's worth being explicit about the trade-offs:
| MCP | JarvisCore Atoms | |
|---|---|---|
| Architecture | Client + server processes | Plain Python functions, no server |
| Discovery | MCP client discovers tools at runtime from the server | Registry lookup; JIT generation if missing |
| Transport | JSON-RPC over stdio/HTTP | Direct Python call in sandbox |
| Versioning | Server manages versions | Immutable _v1, _v2 files + SHA256 |
| Execution history | Not tracked | Tracked — drives candidate→verified→golden promotion |
| New tools | Write a new MCP server handler | CoderSubAgent generates the atom JIT from a task description |
| Auth | Varies by implementation | Always via Nexus — credentials never in agent code |
Does JarvisCore support MCP tools? Not natively — there is no built-in MCP client. However, CustomAgent is flexible enough to wrap an MCP client directly:
class MCPAgent(CustomAgent):
"""Agent that wraps an existing MCP tool server."""
role = "mcp_bridge"
capabilities = ["mcp_tools"]
async def setup(self):
await super().setup()
from mcp import Client
self.mcp = Client("stdio://./my-server.py")
await self.mcp.connect()
async def run(self, message):
result = await self.mcp.call_tool("my_tool", message.data)
return result
This pattern lets teams adopt JarvisCore's orchestration, memory, and P2P mesh while keeping existing MCP tool servers intact. The atom model and MCP are not mutually exclusive — they operate at different layers.
The pragmatic question for teams evaluating JarvisCore: if you have MCP servers already built and working, wrap them in a CustomAgent. If you are starting fresh, atoms give you versioning, execution history, and JIT generation out of the box.
Further Reading¶
- System Bundles & Integrations Guide — how to use pre-built atoms in agent code
- Nexus: Credential Federation — how
auth_infois populated at call time - AutoAgent Guide — how
CoderSubAgentselects and executes atoms