Skip to content

Getting started

Jennah provides persistent memory infrastructure for AI agents, combining semantic recall, knowledge graphs, and execution history behind a unified API. This guide covers account setup, CLI configuration, memory architecture, and running the memchat reference implementation.

Memory architecture: substrate and cognition

Jennah exposes two API surfaces for managing agent memory:

  • Substrate (memory:query and memory:commit): The direct, low-latency data plane. Callers explicitly manage and query vector chunks, knowledge graph nodes and edges, execution log steps, and metadata. Substrate operations execute deterministically within milliseconds, giving callers full control over record IDs, chunk boundaries, and supersession lifecycles. Use the substrate when an agent framework already implements chunking and entity extraction, or when deterministic control over stored records is required.
  • Cognition / Forming (memory:form): The automated extraction and reconciliation layer. Callers submit raw conversation turns and tool traces. Jennah uses model inference to extract candidate facts and relationships, reconciles them against existing workspace memory to detect contradictions and temporal supersessions, and commits the resulting mutations to the substrate. Processing requires several seconds due to inference, removing the need for external extraction and reconciliation pipelines.
Dimension Substrate (memory:query / memory:commit) Cognition (memory:form)
Input Pre-chunked vectors, graph nodes/edges, log steps Raw conversation turns and tool traces
Extraction Client-managed chunking and entity structuring Automated LLM fact and relationship extraction
Reconciliation Client-specified supersessions Automated contradiction detection and supersession
Latency Milliseconds Seconds (model inference)
Identifiers Client-provided IDs Deterministic, content-derived IDs
Use cases Structured ingestion, custom pipelines, low write latency Automated conversation memory without custom pipelines

Both surfaces target the same storage engine and enforce identical enterprise and workspace isolation boundaries. The cognition engine writes through substrate primitives, allowing manual commits and automated formation to coexist within the same workspace.

1. Authentication and enterprise setup

Access to Jennah requires an enterprise account and an API key. Initial sign-in automatically provisions an enterprise organization, assigning the authenticated user as the root administrator. Teammates can be invited subsequently.

Open the console

  1. Authenticate with Google or GitHub.
  2. An enterprise workspace is provisioned automatically upon initial sign-in.
  3. New enterprises start with a 30-day trial at Pro allowances. When the trial ends, the enterprise continues on the Free plan: nothing is paused and existing memory stays in place.

Plans and limits

Every allowance applies to the whole enterprise, not to a key or a member. Formation allowances are counted in formation units.

Free Trial (30 days) Pro Scale Team
Formation units 10 per UTC day 550 for the whole trial 550 / month 1,800 / month 6,500 / month
Formation overage not available not available on AWS Marketplace plans, up to a limit you set on AWS Marketplace plans, up to a limit you set on AWS Marketplace plans, up to a limit you set
Formations in progress 1 at least 8 at least 8 at least 16 at least 32
Largest formation submission 8,192 tokens 16,384 tokens 16,384 tokens 16,384 tokens 16,384 tokens
Agent workspaces / subject scopes 5 / 5 25 / 25 1,000 / 100,000 5,000 / 500,000 25,000 / unlimited
Chunks per workspace or scope 25,000 100,000 100,000 250,000 500,000
Formation output tokens 50,000 per UTC day no daily limit no daily limit no daily limit no daily limit
Memory and data queries 1,000 per UTC day, 5 per second 20,000 per UTC day, 20 per second no daily limit no daily limit no daily limit
Memory writes 1,000 items per UTC day, 2 per second 50,000 items per UTC day, 20 per second no daily limit no daily limit no daily limit
Largest memory item 8,192 bytes (log steps 32,768) no limit no limit no limit no limit
Application datastore not included included included included included
API keys / members 5 / 5 5 / 5 25 / 25 50 / 50 100 / 100

On Free:

  • A request past a limit is refused with RESOURCE_EXHAUSTED and a message naming the limit and when it resets. Nothing is charged as overage.
  • Formation runs at the model's default reasoning level, so extracted memory can differ from what the same conversation produced during the trial.
  • Formations run one at a time. A formation sent while another is in progress can be refused with RESOURCE_EXHAUSTED and a retry delay. The client SDKs do not retry this automatically, so retry it yourself once the delay has passed.
  • Each formation model call may produce up to 32,768 output tokens, the model's reasoning included, and formations may produce 50,000 output tokens a day in total. A formation that reaches what is left of the day's output stops, writes nothing, and still uses its formation units; the next one is refused until the allowance resets.
  • Memory writes (memory:commit, and superseding a chunk or an edge) count one item for each chunk, node, edge, log step, and supersession a request carries, including rewrites of items that already exist. A request that would pass the day's allowance is refused whole. The memory a formation writes does not count.
  • A chunk's raw content, a node's label and properties, an edge's relationship type and properties, and their metadata may total at most 8,192 bytes per item; a precomputed embedding does not count. A log step's thought process, tool used, tool input, and tool output, with its metadata, may total at most 32,768 bytes. A request carrying a larger item is refused whole with INVALID_ARGUMENT naming the item.
  • Each agent workspace and subject scope may hold at most 25,000 chunks, superseded chunks included, so a Free enterprise holds at most 250,000. A write that would add chunks past a scope's ceiling is refused whole with RESOURCE_EXHAUSTED naming the scope, its current count and the limit; rewriting chunks the scope already holds is not refused. See the per-scope volume ceiling.
  • Inspecting memory is limited by the per-second rate but does not count against the daily query allowance, and the queries a formation makes on its own do not count either.
  • Datasets created during the trial can still be read, queried, and deleted, but not written to, and no new datasets can be created.
  • A Free enterprise with no activity for 90 days is permanently deleted, with every agent workspace, its memory, and its datasets. Owners and administrators are emailed 30 days and 7 days before, and any use of the account (a sign-in, or any request with one of its API keys) cancels the deletion.

Generate an API key

API keys authenticate requests from the CLI, client SDKs, and agent runtimes. Keys are scoped to the active enterprise. Generating an API key requires the iam.apikeys:create permission, held by the root and admin roles or granted through a custom role.

A new key has no access to agent workspaces by default. The examples below grant access to demo.* because the demo agents create workspaces under that prefix.

Navigate to Settings → API keys, enter a label (such as memchat), enter demo.* under Agent access, optionally select permission scopes, then select Create key and copy the generated secret key.

After installing the CLI and signing in with jnh login:

jnh keys create --label memchat --agents 'demo.*'

Creating an API key requires an interactive login. If JENNAH_API_KEY is set in your environment, unset it first.

curl -sX POST https://jennah.alphaus.cloud/v1/apikeys \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"label":"memchat","agent_selectors":["demo.*"]}'

The generated secret key (prefixed with jennah_sk_) is displayed only once upon creation.

Secret key retention

Jennah stores only a one-way cryptographic hash of the API key. If the secret key is lost, the key must be revoked and recreated.

2. Install the CLI

jnh supports browser-based OAuth (Google and GitHub) and device-code flows for headless or SSH sessions, communicating over standard HTTP/JSON:

brew install flowerinthenight/tap/jnh
curl -fsSL https://storage.googleapis.com/jennah-cli-dist/install.sh | bash
irm https://storage.googleapis.com/jennah-cli-dist/install.ps1 | iex

Authentication and basic usage

Run the following commands to authenticate and verify access:

jnh version

# Google OAuth (default); use --provider github to switch
jnh login

# Headless/SSH: outputs a one-time verification code
jnh login --device

# Display authenticated user identity and active enterprise
jnh whoami

Authentication tokens are cached locally and refreshed automatically. Once authenticated, manage agent workspaces and inspect stored memory:

jnh agents list
jnh agents create my-agent
jnh agents memory query my-agent --text "..."

# Update jnh binary to the latest release
jnh upgrade

Version pinning and custom paths

Export JENNAH_VERSION=jnh-v1.2.3 before running the installation script to pin a specific release version, or set JENNAH_INSTALL_DIR to specify a custom target directory.

Upgrading Homebrew installations

When jnh is installed via Homebrew, use brew upgrade jnh rather than jnh upgrade so Homebrew tracks updates.

3. Reference implementation: memchat

memchat is a reference CLI application demonstrating persistent agent memory. It is available in three implementations with the same behavior: a Python version built on the Python SDK, a TypeScript version built on the TypeScript SDK (both over gRPC, authenticated with an API key or a jnh login session), and a Go version that calls the HTTP/JSON API with an API key (jennah_sk_).

By default, memchat uses the cognition layer (memory:form), submitting raw conversation exchanges to Jennah for automated fact extraction, relationship mapping, and contradiction reconciliation. The local chat model only generates conversational responses.

Passing the --authored flag (-authored in the Go version) switches execution to the substrate layer (memory:commit). In this mode, the client performs local fact extraction via model tool calling (remember_fact) and explicitly commits graph nodes, edges, and vector records.

Prerequisites

  • A valid Jennah API key (from Step 1) on an active enterprise. The Python and TypeScript versions also accept a jnh login session.
  • Access to an LLM provider:
    • Anthropic: ANTHROPIC_API_KEY
    • Claude on Amazon Bedrock: an AWS profile allowed to call bedrock:InvokeModel on the global.anthropic.claude-sonnet-5-5 inference profile
    • Google Gemini via Vertex AI: Google Cloud project configured with Application Default Credentials (gcloud auth application-default login)
    • Google Gemini via AI Studio: GEMINI_API_KEY (or GOOGLE_API_KEY)
  • Python 3.10 or later, Node.js 22.12 or later, or Go 1.21 or later.

Setup and execution

Install or build memchat, then set your Jennah API key:

pip install \
  git+https://github.com/nightblue-io/jennah-memchat-py
# API key from Step 1
export JENNAH_API_KEY=jennah_sk_...
git clone https://github.com/nightblue-io/jennah-memchat-ts/
cd jennah-memchat-ts/
# Install dependencies and build
npm install
# Put memchat-ts on your PATH
npm install -g .
# API key from Step 1
export JENNAH_API_KEY=jennah_sk_...

To try it without cloning, npx github:nightblue-io/jennah-memchat-ts runs it directly.

git clone https://github.com/nightblue-io/jennah-memchat/
cd jennah-memchat/
# Build local binary
go build -o memchat .
# API key from Step 1
export JENNAH_API_KEY=jennah_sk_...

Configure one model provider:

# Provider option A: Anthropic
export ANTHROPIC_API_KEY=sk-ant-...

# Provider option B: Claude on Amazon Bedrock
# Nothing to export; when you run it, add:
#   --provider bedrock --aws-profile my-profile

# Provider option C: Gemini via Vertex AI (GCP project with ADC)
gcloud auth application-default login
export GOOGLE_GENAI_USE_VERTEXAI=true
export GOOGLE_CLOUD_PROJECT=my-gcp-project
# Optional; defaults to "global"
export GOOGLE_CLOUD_LOCATION=us-central1

# Provider option D: Gemini via Google AI Studio
export GEMINI_API_KEY=...                # or GOOGLE_API_KEY

Then run it:

memchat --verbose
memchat-ts --verbose
./memchat -verbose

The --provider auto flag (default) selects Anthropic when ANTHROPIC_API_KEY is set, falling back to Gemini if Google Cloud or Gemini credentials are detected. It never selects Bedrock. Provider selection can be forced using --provider anthropic, --provider bedrock, or --provider gemini. With Bedrock, --aws-region defaults to ap-northeast-1, and --aws-profile names the AWS profile that signs requests. Use it rather than AWS_PROFILE: when AWS_ACCESS_KEY_ID is also exported, it silently takes precedence over AWS_PROFILE, and the calls run in that key's account instead. At startup, the application logs the active model configuration (for example, chat model: anthropic/claude-sonnet-5-5 or chat model: bedrock/global.anthropic.claude-sonnet-5-5). The TypeScript version's command is memchat-ts, with the same flags. The Go version takes the same flags with a single dash (-provider, -verbose, -authored).

Memory formation trace

Running with --verbose outputs the detailed formation receipt for each dialogue turn, showing extracted candidate records and reconciliation decisions:

you> Hi, I'm Kenji and I lead the platform team at Nightblue.
     I live in Sapporo.

memo> Hi Kenji, great to meet you! Leading the platform team at
      Nightblue from Sapporo sounds like an exciting setup.
  forming memory from 2 turn(s), key frm_sess_0c0409bf_1 ...
  new      Kenji leads the platform team at Nightblue.
  new      Kenji lives in Sapporo.
  new      Kenji works at Nightblue
  new      Kenji lives in Sapporo
  formed: log=1 vec=2(+0 superseded) nodes=4 edges=2(+0 superseded)

In this exchange, the input produces candidates across two storage primitives: - Facts: Stored as text chunks in vector index space for semantic recall. - Relationships: Stored as nodes and directed edges in the knowledge graph.

A single statement can yield both fact chunks and graph relationships. Each candidate receives an explicit evaluation decision: new, revised, known, or rejected. Without --verbose, the interface outputs a summary count (for example, [formed: 4 new]).

Because formation runs model inference and candidate retrieval prior to committing, writes require several seconds to complete, compared to millisecond execution times for direct memory:commit operations. See Candidate decisions for the complete decision taxonomy.

Cross-session recall and provenance

Terminating the process (/exit or Ctrl+D) and restarting it demonstrates persistent memory across sessions. State persistence is maintained by preserving agent_instance_id in memchat-state.json (removing this file resets state to an uninitialized agent instance):

you>   recalled 2 fact(s), 2 past snippet(s):
    · Kenji works at Nightblue
    · Kenji lives in Sapporo
    ~ Kenji lives in Sapporo.  [formed by frm_19fb..., turn(s) 0]

The [formed by ...] annotation indicates record provenance. Memory produced through memory:form attaches reserved, immutable jennah.* metadata attributes identifying the originating formation ID and conversation turn index. These system attributes cannot be overwritten by client callers. See Provenance.

Contradiction reconciliation and temporal history

When new input contradicts established records, the reconciliation pipeline marks the earlier assertion as superseded (retired) and records the updated fact:

you> Actually I moved to Tokyo last month.
  known    Kenji leads the platform team at Nightblue.
  revised  Kenji lives in Tokyo, having moved there from Sapporo.
  formed: log=1 vec=0(+1 superseded) nodes=0 edges=0(+0 superseded)
  [memory] 1 earlier assertion(s) retired by a correction in this turn

During reconciliation, a revised decision records the ID of the assertion it supersedes (for example, (retired fct_8b2bb70a...)), known identifies redundant existing data, and rejected records any proposed candidate discarded during validation, along with the reason.

Superseded records are retired rather than permanently deleted. Each record maintains an active validity window; superseding a record closes its validity timestamp range while opening a new validity window for the replacement.

Standard queries return only currently valid records, so asking where Kenji lives now matches the Tokyo record. To see the retired one, query as of an instant before the correction; the table then shows each match's validity window:

jnh scopes memory query <agent-id> --limit 1 \
  --text "where does Kenji live" --as-of-valid 2026-09-01 \
  --fields content,validAt,invalidAt
CONTENT                  VALID FROM            VALID TO
Kenji lives in Sapporo.  2026-08-20T03:12:09Z  2026-10-07T02:41:55Z
as of valid 2026-09-01T14:59:59.999999999Z

A match with a VALID TO has been retired since the instant you asked about. memory:query requests accept the same point-in-time and historical retrieval parameters. See Temporal memory.

Substrate direct mode

Running memchat with the --authored flag bypasses automatic cognition and directly exercises the substrate layer. The application uses tool calling (remember_fact) to perform local extraction, constructs graph nodes, edges, and vectors with client-managed identifiers, and commits records using memory:commit:

  stored fact: user plays shakuhachi
  stored fact: user has teacher Watanabe-sensei
  committed: log=1 vec=1 nodes=2 edges=2 @ 2026-09-22T03:35:47Z

Substrate writes execute with millisecond latency and deterministic record control, placing responsibility for entity extraction, normalization, and supersession logic on the client application.

Schema alignment with vocabularies

Without schema constraints, formation produces ad-hoc entity names and relation labels based on model completion. Declaring a vocabulary injects structured entity classes and relationship definitions into the extraction prompt. Vocabularies guide extraction schemas without strictly rejecting out-of-vocabulary entities.

Declaring a vocabulary requires administrative credentials (such as an authenticated CLI session). To configure a workspace with a predefined vocabulary and test it with memchat (the example vocabulary.yaml ships in the Go repository and works with every version):

jnh agents create demo.memchat_vocab --wait
jnh vocabulary declare --scope demo.memchat_vocab \
  --from-file vocabulary.yaml
memchat --verbose --agent demo.memchat_vocab
# TypeScript: memchat-ts --verbose --agent demo.memchat_vocab
# Go: ./memchat -verbose -agent demo.memchat_vocab

This vocabulary.yaml specifies 6 entity classes and 9 relationship types. Applying this configuration changes graph topology during extraction:

Metric Without vocabulary With vocabulary.yaml
Nodes 5 6 (identifies platform team)
Edges 4 6 (identifies LEADS and PART_OF)
Classifications None All nodes classified

Without a vocabulary, the statement "I lead the platform team at Nightblue" collapses to Kenji -WORKS_AT-> Nightblue, omitting the team entity. Declaring Team as a distinct class allows the extraction pipeline to preserve intermediate organizational entities and their relations:

Kenji         -LEADS->   platform team
platform team -PART_OF-> Nightblue

Subsequent graph queries can filter traversals and lookups by assigned entity class (for example, Person, Organization, Team, Place, Interest).

Vocabulary read permissions

Printing the active vocabulary during startup requires the agent.vocabulary:read permission on the API key. If the key lacks this permission, memchat displays an informational notice while extraction continues to apply the declared vocabulary.

Next steps

  • Consult the API Reference for endpoint specifications.
  • See Forming memory for details on conversation ingestion, candidate generation, and reconciliation logic.
  • See Content chunking and Retrieval channels for configuring vector chunks and substrate queries.
  • See Memory vocabulary for schema configuration across entity classes and relationship types.
  • Review the memchat source (Python, TypeScript, Go) for implementation examples of memory:form and direct memory:query / memory:commit operations.