Skip to main content
Agent history and recipes are just rows. The agent extension stores what your runtime already produces.

1. Enable the Extension

The optional built-in agent extension persists agent runtime history and recipes as ordinary workspace entities. It does not replace hb.LLM, LLMSession, prompts, Toolkits, or MCP — it stores the pieces those systems already use.
import heavenbase as hb

ws = hb.HeavenBase("agent-memory", preset="debug")
ws.enable_extension("agent")
The rule: the classes (hb.Agent, hb.Session, hb.Message, hb.Skill) import anywhere, but workspace rows require enablement. The class save/load helpers enable the extension on their target workspace automatically, so an explicit enable_extension("agent") is only needed when you want to query the rows yourself first.

2. Persistent Entities

The extension registers four entities:
Entity idClassStores
agent-messagehb.MessageOne OpenAI-format payload plus role, content_text, and tool_call_count query projections
agent-sessionhb.SessionOrdered message_ids, turn_count, tool_call_count, runtime state, and aggregated usage
agent-skillhb.SkillParsed SKILL.md frontmatter, skill_body, toolkit_refs, and a deterministic zip archive
agent-agenthb.AgentA recipe: llm_preset, prompt_ref, skill_refs, toolkit_refs, and runtime args
The stored Message.payload is the canonical OpenAI-format dictionary. The projections exist for query and Catalog discovery, not as a second source of truth.

3. Logged CLI Runs

hb llm chat writes one agent-session row and ordered agent-message rows after the response completes. hb llm session creates one persistent session when the interactive session starts, then appends each completed user/assistant/tool iteration. The CLI output shape is unchanged. Inspect logged history through the active workspace:
sessions = ws.rows(hb.Session)
messages = ws.rows(hb.Message)
payloads = hb.Session.load(sessions[0]["object_id"], ws=ws).messages()
Session.messages() returns OpenAI-format payloads in session order, ready to feed back into a runtime session.

4. Skills

Create a Skill from a folder containing SKILL.md:
skill = hb.Skill.from_path("skills/sql-analyst")
skill.save(ws=ws)
SKILL.md frontmatter may declare Toolkit refs with toolkit::
---
name: sql-analyst
description: Analyze SQL-backed product data.
toolkit:
  - analytics/sql-tools:1
---
Skill folders are stored as deterministic zip bytes under archive. Use the runtime read_skill tool when an agent needs file contents:
toolkit = hb.Skill.toolkit([skill], ws=ws)
text = toolkit.run("read_skill", skill_name=skill.name, path="SKILL.md")

5. Agent Recipes

An hb.Agent row is a recipe, not a second runtime stack:
agent = hb.Agent(
    name="demo-agent",
    llm_preset="chat",
    prompt_ref="demo.agent.system",
    skill_refs=["sql-analyst"],
    toolkit_refs=["analytics/sql-tools:-1"],
    args={"max_steps": 8},
    ws=ws,
)
agent.save()

runtime = hb.Agent.load("demo-agent", ws=ws).build()
runtime.session.send("Use the available skills.", max_tool_turns=8)
build() resolves hb.LLM, hb.Prompt, hb.Skill, and registered hb.Toolkit refs, then returns an AgentRuntime whose session is a normal LLMSession with tools attached. Use agent.new_session() when you want a persistent hb.Session row for a future run.
The extension covers single-agent recipes today. Multi-agent orchestration is future work.

Further Exploration

Related resources:
  • Agents - LLM sessions, prompts, workspace memory, and MCP tools
  • Extensions - How entity extensions register and enable
  • Sessions - The runtime LLMSession that recipes build
  • Toolkits - Registered Toolkit refs that recipes attach