Skip to content

TrueSelph/jvagent

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

834 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

jvagent

GitHub release (latest by date) GitHub Workflow Status PyPI version GitHub issues GitHub pull requests GitHub

A modular AI-agent harness for your application. Declare multi-tenant, multi-agent, Claude-style agents in YAML and serve them over HTTP — with persistent per-user memory, a load-on-demand plugin system, drop-in Anthropic Agent Skills, built-in messaging-channel delivery, and a single-loop Orchestrator that turns every incoming message into tool calls. No hand-written state machine, no glue code to ship an agent.

The model is the pilot. Tools are the controls. Skills are the flight plan. jvagent is the airframe — the production harness that holds it together.

Table of Contents

Overview

jvagent is built on jvspatial's object-spatial graph framework. Everything an agent knows and does is a Node or Edge: the agent, its actions, and its per-user memory all live in one graph that persists across turns and processes.

An app declares one or more agents in app.yaml / agent.yaml. Each agent owns a graph of actions (namespaced plugins, loaded on demand) plus a per-user memory subgraph (User → Conversation → Interaction). Traffic at POST /agents/{id}/interact becomes an Interaction; the Orchestrator runs the whole turn in one execute() — a deterministic continuation check (resume an in-flight flow) followed by a bounded think-act-observe loop over a unified tool surface. Routing is tool selection. Turn-lock is an active flow that hasn't returned COMPLETE.

Most agent frameworks hand you a Python library and leave the production concerns — tenancy, persistence, auth, channels, deployment — as an exercise. jvagent ships them. It is the harness you wrap around the model: many agents per app, isolated state per user, the same agent voiced to WhatsApp / Messenger / email / web, and Anthropic Agent Skills dropped into a per-user sandbox without writing Python.

Use cases: multi-tenant SaaS assistants, customer-support and sales bots across messaging channels, document-grounded copilots, and long-running autonomous agents — embedded in your application, not a hosted black box.

Why jvagent

🏢 Multi-tenant by construction

Every user's entire history is a connected subgraph (User → Conversation → Interaction), so isolation is a property of the data model, not a WHERE user_id = you have to remember. Claude/Anthropic skills run in a per-user code-execution sandbox (ADR-0017); deleting a tenant is one edge-walk.

👥 Many agents, one app

Declare any number of agents in app.yaml / agent.yaml, each with its own actions, identity, memory, and tool surface — one deployment, many distinct bots. Namespaced plugins (jvagent/, contrib/, custom/) keep third-party actions from colliding.

🧩 Drop-in Anthropic Agent Skills

A standard Anthropic Agent Skill folder (SKILL.md + scripts/, agentskills.io-compatible) activates as a tool: the Orchestrator stages it into the caller's sandbox and the model runs its scripts. Bring Claude's skill ecosystem into your own app — no rewrite. See docs/ORCHESTRATOR.md.

🧠 One-loop Orchestrator, not a state machine

A single action (weight -200) runs each turn in one execute(): resume an active flow if one is locked, otherwise let the model think-act-observe over every available tool. Adding a capability means adding a tool — there is no separate router, intent classifier, or capability registry to maintain. See docs/ORCHESTRATOR.md.

🪶 Thin harness

The server stays out of the model's way. Steering, extraction, and orchestration live in skills (Markdown SOPs) and the model's own tool calls — not in server-side special-casing. This keeps behavior predictable and the codebase small. See docs/thin-harness.md.

🔌 Load-on-demand actions

Actions are namespaced plugins discovered from info.yaml. Only what an agent lists (and its transitive dependencies) is imported; everything else stays dormant and its endpoints stay closed. Deep lifecycle hooks (on_register, on_enable, on_startup, on_disable, on_deregister, pulse) make enable/disable dynamic and safe.

🗂️ Skills (Markdown-first)

Skills add procedures as Markdown with optional Python tool scripts — Claude-compatible bundles you can drop in without touching Python. The interview skill drives multi-field, validated data collection on top of the same tool surface. See jvagent/skills/README.md.

💾 Persistent, self-pruning memory

User → Conversation → Interaction is a bidirectional chain. Rolling-window pruning keeps latency predictable (capped per call), and a separate logs database keeps interaction/error trails out of the hot path. See .planning/reference/memory-and-pruning.md.

📣 Channels & proactive messaging

A response bus with channel adapters delivers replies to WhatsApp, Messenger, email, or the web, and Agent.send_proactive_message lets an agent reach out between turns. See docs/proactive-messages.md.

🛠️ Production-shaped

Distributed conversation locks (Redis / DynamoDB), per-event-loop locking for serverless warm starts, model HTTP retries with backoff, MCP tool gateway, and light/heavy model gearing — all configurable from YAML.

How jvagent compares

Most agent frameworks are libraries that orchestrate model calls; you bring the server, the tenancy, the persistence, and the channels. jvagent is a harness — it ships those. The table below maps each project against its primary, native design as of mid-2026 (most gaps are bridgeable with extra code; this is about what you get out of the box).

jvagent LangGraph CrewAI AutoGen / AG2 Letta Agno / AgentOS
Primary form Harness + HTTP server Orchestration library Orchestration library Conversation library Memory-agent runtime Framework + runtime
Define an agent in YAML (declarative) Python Python (+ some YAML) Python Python / API Python
Many agents per deploy ✅ first-class ➖ you compose ✅ crews ✅ teams ✅ teams
Per-tenant / per-user isolation ✅ by data model ➖ DIY ➖ DIY ➖ DIY ✅ memory-scoped ✅ per-session
Persistent memory model ✅ graph (User→Conv→Interaction) + pruning ✅ checkpoints ➖ task passing ➖ in-context ✅ OS-tiered memory ✅ sessions + knowledge
Built-in messaging channels ✅ WhatsApp / Messenger / email / web / SSE ❌ (API) ➖ Slack / AG-UI
Drop-in Anthropic Agent Skills SKILL.md → per-user sandbox ➖ via Claude Agent SDK
HTTP API + auth out of the box ➖ via Platform ✅ server ✅ FastAPI
Routing model picks tools (no router) explicit graph edges role/process conversation agent loop model + teams
License MIT MIT MIT (Apache/MIT) Apache-2.0 MPL-2.0

✅ native · ➖ partial / with setup · ❌ not built in. Where to reach for each: LangGraph when you want to hand-draw a control graph with checkpoints; CrewAI/AutoGen for quick multi-agent prototypes; Letta when self-managing long-term memory is the whole point; Agno for a polished Python-first production runtime. Reach for jvagent when you want to embed multi-tenant, multi-agent, Claude-skill-capable agents into your own application and have the harness — memory, channels, auth, deployment — already solved.

Comparisons reflect each project's primary documented design and are not exhaustive; all of these are capable frameworks. Corrections welcome via issue or PR.

Installation

# From PyPI
pip install jvagent
# From source (development)
git clone https://github.com/TrueSelph/jvagent.git
cd jvagent
pip install -e ".[dev]"

Requires Python 3.8+. Optional extras: pageindex (document ingestion/retrieval), distributed-lock (Redis / DynamoDB conversation locks), test, dev.

Pre-1.0 release candidates publish to TestPyPI first:

pip install -i https://test.pypi.org/simple/ \
    --extra-index-url https://pypi.org/simple/ jvagent==0.1.0rc5

Quick Start

1. Scaffold an app

jvagent app create --yes \
  --dir ./my_app \
  --app-id my_app \
  --title "My App" \
  --author "Your Name" \
  --agent jvagent/main_bot@minimal \
  --profile minimal

This writes app.yaml, agents/, profiles/, and .env.example. Built-in agent profiles include minimal, conversational, whatsapp_voice, and research. Full CLI reference: docs/scaffolding.md.

2. Configure the environment

cd my_app
cp .env.example .env

Set at minimum:

  • JVAGENT_ADMIN_PASSWORD — the initial admin user's password.
  • JVSPATIAL_JWT_SECRET_KEY — JWT signing secret (change from the default for any non-local use).

Add a model provider key (e.g. OPENAI_API_KEY) for the agent to reason. See the configuration reference and environment keys.

3. Run

jvagent                 # uses the current directory as the app root
jvagent /path/to/my_app # or point at an app root explicitly
jvagent /path/to/my_app --update --debug

The server starts on http://127.0.0.1:8000 (configurable). Interactive API docs are at /docs and /redoc.

4. Talk to the agent

# Log in with the admin credentials from .env
curl -X POST http://localhost:8000/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email": "admin@jvagent.example", "password": "your-admin-password"}'

# Send a turn (use the token from the login response)
curl -X POST http://localhost:8000/agents/{agent_id}/interact \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"utterance": "Hello"}'

5. Or use the chat UI

The bundled jvchat web UI ships in the wheel and runs on its own port (a separate origin from the agent server, by design):

jvagent chat                                      # http://127.0.0.1:3000, opens a browser
jvagent chat --url https://my-agent.example.com   # point at a remote agent

A complete worked example ships in examples/jvagent_app/ — an Orchestrator-pattern agent with a skill bundle. See its STRUCTURE for the file-by-file tour, and the local dev runbook to run it end-to-end.

Core Concepts

Graph hierarchy

Root → App → Agents → Agent ─┬─ Actions → Action(s) → [InteractAction subclass]
                             └─ Memory → User → Conversation → Interaction*

The graph is the source of truth. Top-level InteractActions are visited by the InteractWalker in ascending weight order; the Orchestrator sits at the front (weight -200) and runs the turn.

Actions

An Action is a namespaced plugin (namespace/action_name) declared by an info.yaml. Persisted fields use attribute(...) so they live on the graph; plain class attributes do not persist. Actions expose tools via get_tools(), discover peers with get_action(), and honor lifecycle hooks. InteractActions additionally participate in a turn and can be dispatched as tools by the Orchestrator. To build one, start with the action authoring contract.

The turn

POST /agents/{id}/interact
        │
        ▼
  new Interaction ──> InteractWalker (weight order)
        │
        ▼
  Orchestrator.execute()
        ├─ continuation check ── resume a locked flow?
        └─ think → act (tools) → observe ──┐
                  ▲────────────────────────┘  (bounded loop)
        │
        ▼
  ReplyAction.gather() ── one unified reply per turn

ReplyAction (jvagent/reply) is jvagent's single output contract: producers queue directives; ReplyAction gathers them and delivers exactly one emission per turn. Identity (alias + role) lives on the Agent node. See ADR-0024 / ADR-0025.

Memory

Each user gets a Conversation holding a bidirectional chain of Interactions. Conversation.interaction_limit sets the rolling window (0 disables); pruning is capped per call for predictable latency. Full API in jvagent/memory/README.md.

Skills

A skill is a Markdown SOP (optionally plus Python tool scripts) that extends an action's behavior without new Python wiring. The interview skill, for example, layers validated multi-field collection onto the orchestrator's tool surface. See jvagent/skills/README.md and the thin-harness guide.

Configuration

jvagent resolves configuration by precedence (highest first):

  1. CLI flag (--update, --source, --merge, --debug, --serverless)
  2. Environment variable (via jvspatial.env.env)
  3. app.yaml (app root)
  4. agent.yaml (under agents/)
  5. Action attribute(default=...)

app.yaml stays lean; per-agent and per-action settings live on the agent and action nodes. See the configuration reference, the full configuration keys, and integration env vars.

Documentation

Getting started & operating

Architecture & internals

Action modules

Deployment & tooling

Example application

For AI agents & contributors

Agent-facing design docs live under .planning/; the root CLAUDE.md is the entry point (also surfaced as AGENTS.md).

Authors & maintainers

jvagent — an agent harness built on jvspatial — was created by Eldon Marks (@eldonm), who serves as its lead maintainer.

See AUTHORS for the full list of authors and contributors. Copyright and licensing terms are set out in the LICENSE file.

Contributors

Contributing

Contributions are welcome. Please read the Contributing Guide for the dev loop, conventions, and the CI gates, and the Code of Conduct before opening a pull request. Security issues: see the Security Policy.

License

This project is licensed under the MIT License — see the LICENSE file for details.

About

A modular agentive framework built on top of jvspatial

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors