* feat(api): add bank template import/export endpoints
Add POST /banks/{bank_id}/import and GET /banks/{bank_id}/export
endpoints for declarative bank setup via JSON manifests.
A template manifest (version 1) can include bank config overrides
and mental model definitions. Import creates or updates mental
models matched by id, applies config as per-bank overrides, and
returns async operation IDs for content generation.
Export dumps a bank's explicit overrides and mental models as a
manifest that can be re-imported into another bank.
Includes control plane UI: bank creation dialog now accepts an
optional template JSON to pre-configure the bank on creation.
* docs: add Template Gallery page and bank templates reference
- Template Gallery (/templates) with search, category filter, manifest
preview modal with copy-to-clipboard
- 5 starter templates: Customer Support, Research Assistant, Personal
Journal, Code Review Buddy, Meeting Notes
- Bank Templates API reference doc (developer/api/bank-templates)
- Sidebar entry under API section
* docs: add Template Gallery links to navbar and sidebar
- Top navbar: "Templates" link between Integrations and Changelog
- Sidebar: "Template Gallery" in Resources section
* fix(docs): remove emoji icons, autofocus search, fix placeholder in template gallery
* docs: rename to Bank Templates, move to Resources sidebar only
* docs: add Bank Templates to Resources navbar dropdown
* feat(api): add directives to bank template import/export
- Add BankTemplateDirective model with name, content, priority, is_active, tags
- Import creates/updates directives matched by name
- Export includes all directives (active and inactive)
- Validation: duplicate names rejected, empty name/content caught
- Tests: 24 tests covering directives create/update, existing vs new
bank import, validation, export with directives, full round-trip
* docs: add directives to bank templates docs and sample templates
* feat(api): add JSON Schema endpoint for bank template validation
- GET /v1/default/bank-template-schema returns the JSON Schema
auto-generated from the Pydantic BankTemplateManifest model
- Static schema file at docs/static/bank-template-schema.json
- Docs updated with schema endpoint, static file link, and
validation examples (Python jsonschema, Node ajv-cli)
* feat(api): live schema validation on import, fix schema endpoint path
- Move schema endpoint to /v1/bank-template-schema (system-level, not per-bank)
- Import endpoint now accepts raw JSON and validates with Pydantic manually,
returning clean 400 errors instead of raw 422s for all validation failures
- All validation (schema + semantic) returns consistent 400 with detailed messages
* docs: add interactive JSON Schema viewer to Bank Templates page
Renders the Pydantic-generated schema as a collapsible property tree
with types, required badges, defaults, and descriptions. The schema
is imported from the static bank-template-schema.json file.
* ui: add template toggle switch and browse link to bank creation dialog
- Replace always-visible textarea with a switch toggle ("Import from template")
- Textarea only shows when switch is on, keeping the dialog clean by default
- Add "Browse templates" link pointing to hindsight.vectorize.io/templates
- Reset template state when switch is toggled off or dialog is cancelled
* ui: add empty state with Add Document CTA to data view
When a bank has 0 memories, the data view (all tabs: constellation,
graph, table, timeline) shows a centered empty state with a CTA
button that opens the Add Document dialog.
* docs: replace templates with Conversation and Coding Agent
Remove generic placeholder templates. Add two practical templates
based on actual integration patterns:
- Conversation: for chat agents (LiteLLM, LangGraph, Pydantic AI,
Vercel AI SDK). Tracks user preferences, open threads.
- Coding Agent: for Claude Code/Codex. Tracks technical decisions,
project context, developer preferences. High literalism.
* docs: rename gallery to Bank Templates Hub, keep API doc as Bank Templates
* docs: register layout-template and file-json icons in navbar and sidebar
* docs: register layout-template icon in DefaultNavbarItem for dropdown items
* docs: show integration icons on template cards
Templates now have an optional `integrations` field referencing
integration IDs from integrations.json. Icons are resolved at render
time and shown in the card header next to the category badge.
* docs: add Personal Assistant template for OpenClaw, Hermes, NemoClaw
* feat: add Export Template to bank actions + map all integrations to templates
- Add "Export Template" to the bank Actions dropdown — exports config,
mental models, and directives as JSON, copies to clipboard
- Add export API route and client method
- Map remaining integrations to templates: CrewAI, AG2, Agno, Strands,
LlamaIndex, local-mcp, skills → Conversation; hindclaw → Personal Assistant
* feat: add --template flag to LoCoMo benchmark + remove schema from Hub
- LoCoMo benchmark accepts --template <path> to apply a bank template
manifest (config, mental models, directives) before ingestion
- Template is applied per-bank in both single-phase and two-phase modes
- BenchmarkRunner.apply_template() reuses the same engine methods as
the /import API endpoint
- Remove Manifest Schema section from Bank Templates Hub page
(schema stays in the API reference doc)
* refactor: remove description field from bank template manifest
* docs: remove tags, fact_types, and directives from starter templates
* docs: remove reflect_mission and disposition fields from starter templates
* build: validate template manifests against JSON Schema during docs build
* cleanup: remove unused JsonSchemaViewer component
* docs: remove retain_extraction_mode from starter templates
* ui: enable word wrap in template manifest preview
* docs: add link to Bank Templates reference doc from Hub page
* docs: convert bank templates doc to mdx with multi-language code snippets
- Convert bank-templates.md to .mdx with Tabs/CodeSnippet components
- Add example files: bank-templates.py, .mjs, .sh, .go with doc markers
- Examples cover import, dry-run, export, round-trip, and schema
- Regenerate OpenAPI spec and all client SDKs (Python, TS, Rust, Go)
* fix: migration revision collision + use typed models in benchmark template
- Rename merge migration d6e7f8a9b0c1 -> d6e7f8a9b0c2 to resolve
revision ID collision with case_insensitive_entities_trgm_index
- Update a4b5c6d7e8f9 down_revision to point to the renamed migration
- Fix f-string lint in case_insensitive migration
- BenchmarkRunner.apply_template() now validates manifest through
BankTemplateManifest Pydantic model instead of raw dict access
- Remove redundant inline imports (json, Path already at module top)
* fix(docs): add missing Go tab to dry-run code snippet
* ci: retrigger
* fix: sync skills openapi.json + fix bankId null type error in export
- Copy updated openapi.json to skills/hindsight-docs/references/
- Add null guard for bankId in Export Template onClick handler
* fix: sync generated files (memory_engine formatting, docs skill references)
* cleanup: remove obsolete migration collision workaround
569 lines
15 KiB
JSON
569 lines
15 KiB
JSON
{
|
|
"$defs": {
|
|
"BankTemplateConfig": {
|
|
"description": "Bank configuration fields within a template manifest.\n\nOnly includes configurable (per-bank) fields. Credential fields\n(API keys, base URLs) are intentionally excluded for security.",
|
|
"properties": {
|
|
"reflect_mission": {
|
|
"anyOf": [
|
|
{
|
|
"type": "string"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Mission/context for Reflect operations",
|
|
"title": "Reflect Mission"
|
|
},
|
|
"retain_mission": {
|
|
"anyOf": [
|
|
{
|
|
"type": "string"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Steers what gets extracted during retain",
|
|
"title": "Retain Mission"
|
|
},
|
|
"retain_extraction_mode": {
|
|
"anyOf": [
|
|
{
|
|
"type": "string"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Fact extraction mode: 'concise' (default), 'verbose', or 'custom'",
|
|
"title": "Retain Extraction Mode"
|
|
},
|
|
"retain_custom_instructions": {
|
|
"anyOf": [
|
|
{
|
|
"type": "string"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Custom extraction prompt (when mode='custom')",
|
|
"title": "Retain Custom Instructions"
|
|
},
|
|
"retain_chunk_size": {
|
|
"anyOf": [
|
|
{
|
|
"type": "integer"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Max token size for each content chunk",
|
|
"title": "Retain Chunk Size"
|
|
},
|
|
"enable_observations": {
|
|
"anyOf": [
|
|
{
|
|
"type": "boolean"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Toggle observation consolidation",
|
|
"title": "Enable Observations"
|
|
},
|
|
"observations_mission": {
|
|
"anyOf": [
|
|
{
|
|
"type": "string"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Controls what gets synthesised",
|
|
"title": "Observations Mission"
|
|
},
|
|
"disposition_skepticism": {
|
|
"anyOf": [
|
|
{
|
|
"maximum": 5,
|
|
"minimum": 1,
|
|
"type": "integer"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Skepticism trait (1-5)",
|
|
"title": "Disposition Skepticism"
|
|
},
|
|
"disposition_literalism": {
|
|
"anyOf": [
|
|
{
|
|
"maximum": 5,
|
|
"minimum": 1,
|
|
"type": "integer"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Literalism trait (1-5)",
|
|
"title": "Disposition Literalism"
|
|
},
|
|
"disposition_empathy": {
|
|
"anyOf": [
|
|
{
|
|
"maximum": 5,
|
|
"minimum": 1,
|
|
"type": "integer"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Empathy trait (1-5)",
|
|
"title": "Disposition Empathy"
|
|
},
|
|
"entity_labels": {
|
|
"anyOf": [
|
|
{
|
|
"items": {
|
|
"type": "string"
|
|
},
|
|
"type": "array"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Controlled vocabulary for entity labels",
|
|
"title": "Entity Labels"
|
|
},
|
|
"entities_allow_free_form": {
|
|
"anyOf": [
|
|
{
|
|
"type": "boolean"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Allow entities outside the label vocabulary",
|
|
"title": "Entities Allow Free Form"
|
|
}
|
|
},
|
|
"title": "BankTemplateConfig",
|
|
"type": "object"
|
|
},
|
|
"BankTemplateDirective": {
|
|
"description": "A directive definition within a bank template manifest.\n\nDirectives are matched by name on re-import: existing directives\nwith the same name are updated, new ones are created.",
|
|
"properties": {
|
|
"name": {
|
|
"description": "Human-readable name for the directive (used as match key on re-import)",
|
|
"title": "Name",
|
|
"type": "string"
|
|
},
|
|
"content": {
|
|
"description": "The directive text to inject into prompts",
|
|
"title": "Content",
|
|
"type": "string"
|
|
},
|
|
"priority": {
|
|
"default": 0,
|
|
"description": "Higher priority directives are injected first",
|
|
"title": "Priority",
|
|
"type": "integer"
|
|
},
|
|
"is_active": {
|
|
"default": true,
|
|
"description": "Whether this directive is active",
|
|
"title": "Is Active",
|
|
"type": "boolean"
|
|
},
|
|
"tags": {
|
|
"default": [],
|
|
"description": "Tags for filtering",
|
|
"items": {
|
|
"type": "string"
|
|
},
|
|
"title": "Tags",
|
|
"type": "array"
|
|
}
|
|
},
|
|
"required": [
|
|
"name",
|
|
"content"
|
|
],
|
|
"title": "BankTemplateDirective",
|
|
"type": "object"
|
|
},
|
|
"BankTemplateMentalModel": {
|
|
"description": "A mental model definition within a bank template manifest.",
|
|
"properties": {
|
|
"id": {
|
|
"description": "Unique ID for the mental model (alphanumeric lowercase with hyphens)",
|
|
"title": "Id",
|
|
"type": "string"
|
|
},
|
|
"name": {
|
|
"description": "Human-readable name for the mental model",
|
|
"title": "Name",
|
|
"type": "string"
|
|
},
|
|
"source_query": {
|
|
"description": "The query to run to generate content",
|
|
"title": "Source Query",
|
|
"type": "string"
|
|
},
|
|
"tags": {
|
|
"default": [],
|
|
"description": "Tags for scoped visibility",
|
|
"items": {
|
|
"type": "string"
|
|
},
|
|
"title": "Tags",
|
|
"type": "array"
|
|
},
|
|
"max_tokens": {
|
|
"default": 2048,
|
|
"description": "Maximum tokens for generated content",
|
|
"maximum": 8192,
|
|
"minimum": 256,
|
|
"title": "Max Tokens",
|
|
"type": "integer"
|
|
},
|
|
"trigger": {
|
|
"$ref": "#/$defs/MentalModelTrigger",
|
|
"default": {},
|
|
"description": "Trigger settings"
|
|
}
|
|
},
|
|
"required": [
|
|
"id",
|
|
"name",
|
|
"source_query"
|
|
],
|
|
"title": "BankTemplateMentalModel",
|
|
"type": "object"
|
|
},
|
|
"MentalModelTrigger": {
|
|
"description": "Trigger settings for a mental model.",
|
|
"properties": {
|
|
"refresh_after_consolidation": {
|
|
"default": false,
|
|
"description": "If true, refresh this mental model after observations consolidation (real-time mode)",
|
|
"title": "Refresh After Consolidation",
|
|
"type": "boolean"
|
|
},
|
|
"fact_types": {
|
|
"anyOf": [
|
|
{
|
|
"items": {
|
|
"enum": [
|
|
"world",
|
|
"experience",
|
|
"observation"
|
|
],
|
|
"type": "string"
|
|
},
|
|
"type": "array"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Filter which fact types are retrieved during reflect. None means all types (world, experience, observation).",
|
|
"title": "Fact Types"
|
|
},
|
|
"exclude_mental_models": {
|
|
"default": false,
|
|
"description": "If true, exclude all mental models from the reflect loop (skip search_mental_models tool).",
|
|
"title": "Exclude Mental Models",
|
|
"type": "boolean"
|
|
},
|
|
"exclude_mental_model_ids": {
|
|
"anyOf": [
|
|
{
|
|
"items": {
|
|
"type": "string"
|
|
},
|
|
"type": "array"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Exclude specific mental models by ID from the reflect loop.",
|
|
"title": "Exclude Mental Model Ids"
|
|
},
|
|
"tags_match": {
|
|
"anyOf": [
|
|
{
|
|
"enum": [
|
|
"any",
|
|
"all",
|
|
"any_strict",
|
|
"all_strict"
|
|
],
|
|
"type": "string"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Override how the model's tags filter memories during refresh. If not set, defaults to 'all_strict' when the model has tags (security isolation) or 'any' when the model has no tags. Set to 'any' to include untagged memories alongside tagged ones during refresh.",
|
|
"title": "Tags Match"
|
|
},
|
|
"tag_groups": {
|
|
"anyOf": [
|
|
{
|
|
"items": {
|
|
"anyOf": [
|
|
{
|
|
"$ref": "#/$defs/TagGroupLeaf"
|
|
},
|
|
{
|
|
"$ref": "#/$defs/TagGroupAnd"
|
|
},
|
|
{
|
|
"$ref": "#/$defs/TagGroupOr"
|
|
},
|
|
{
|
|
"$ref": "#/$defs/TagGroupNot"
|
|
}
|
|
]
|
|
},
|
|
"type": "array"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Compound boolean tag expressions to use during refresh instead of the model's own tags. When set, these tag groups are passed to reflect and the model's flat tags are NOT used for filtering. Supports nested and/or/not expressions for complex tag-based scoping.",
|
|
"title": "Tag Groups"
|
|
}
|
|
},
|
|
"title": "MentalModelTrigger",
|
|
"type": "object"
|
|
},
|
|
"TagGroupAnd": {
|
|
"description": "Compound AND group: all child filters must match.",
|
|
"properties": {
|
|
"and": {
|
|
"items": {
|
|
"anyOf": [
|
|
{
|
|
"$ref": "#/$defs/TagGroupLeaf"
|
|
},
|
|
{
|
|
"$ref": "#/$defs/TagGroupAnd"
|
|
},
|
|
{
|
|
"$ref": "#/$defs/TagGroupOr"
|
|
},
|
|
{
|
|
"$ref": "#/$defs/TagGroupNot"
|
|
}
|
|
]
|
|
},
|
|
"title": "And",
|
|
"type": "array"
|
|
}
|
|
},
|
|
"required": [
|
|
"and"
|
|
],
|
|
"title": "TagGroupAnd",
|
|
"type": "object"
|
|
},
|
|
"TagGroupLeaf": {
|
|
"description": "A leaf tag filter: matches memories by tag list and match mode.",
|
|
"properties": {
|
|
"tags": {
|
|
"items": {
|
|
"type": "string"
|
|
},
|
|
"title": "Tags",
|
|
"type": "array"
|
|
},
|
|
"match": {
|
|
"default": "any_strict",
|
|
"enum": [
|
|
"any",
|
|
"all",
|
|
"any_strict",
|
|
"all_strict"
|
|
],
|
|
"title": "Match",
|
|
"type": "string"
|
|
}
|
|
},
|
|
"required": [
|
|
"tags"
|
|
],
|
|
"title": "TagGroupLeaf",
|
|
"type": "object"
|
|
},
|
|
"TagGroupNot": {
|
|
"description": "Compound NOT group: child filter must NOT match.",
|
|
"properties": {
|
|
"not": {
|
|
"anyOf": [
|
|
{
|
|
"$ref": "#/$defs/TagGroupLeaf"
|
|
},
|
|
{
|
|
"$ref": "#/$defs/TagGroupAnd"
|
|
},
|
|
{
|
|
"$ref": "#/$defs/TagGroupOr"
|
|
},
|
|
{
|
|
"$ref": "#/$defs/TagGroupNot"
|
|
}
|
|
],
|
|
"title": "Not"
|
|
}
|
|
},
|
|
"required": [
|
|
"not"
|
|
],
|
|
"title": "TagGroupNot",
|
|
"type": "object"
|
|
},
|
|
"TagGroupOr": {
|
|
"description": "Compound OR group: at least one child filter must match.",
|
|
"properties": {
|
|
"or": {
|
|
"items": {
|
|
"anyOf": [
|
|
{
|
|
"$ref": "#/$defs/TagGroupLeaf"
|
|
},
|
|
{
|
|
"$ref": "#/$defs/TagGroupAnd"
|
|
},
|
|
{
|
|
"$ref": "#/$defs/TagGroupOr"
|
|
},
|
|
{
|
|
"$ref": "#/$defs/TagGroupNot"
|
|
}
|
|
]
|
|
},
|
|
"title": "Or",
|
|
"type": "array"
|
|
}
|
|
},
|
|
"required": [
|
|
"or"
|
|
],
|
|
"title": "TagGroupOr",
|
|
"type": "object"
|
|
}
|
|
},
|
|
"description": "A bank template manifest for import/export.\n\nVersion field enables forward-compatible schema evolution: the API\nauto-upgrades older manifest versions to the current schema on import.",
|
|
"example": {
|
|
"bank": {
|
|
"disposition_empathy": 5,
|
|
"enable_observations": true,
|
|
"reflect_mission": "You are helping a support agent remember customer interactions.",
|
|
"retain_mission": "Extract customer issues, resolutions, and sentiment."
|
|
},
|
|
"directives": [
|
|
{
|
|
"content": "Always respond with empathy and understanding.",
|
|
"name": "Always be empathetic",
|
|
"priority": 10
|
|
}
|
|
],
|
|
"mental_models": [
|
|
{
|
|
"id": "sentiment-overview",
|
|
"name": "Customer Sentiment Overview",
|
|
"source_query": "What is the overall sentiment trend?",
|
|
"trigger": {
|
|
"refresh_after_consolidation": true
|
|
}
|
|
}
|
|
],
|
|
"version": "1"
|
|
},
|
|
"properties": {
|
|
"version": {
|
|
"description": "Manifest schema version (currently '1')",
|
|
"title": "Version",
|
|
"type": "string"
|
|
},
|
|
"bank": {
|
|
"anyOf": [
|
|
{
|
|
"$ref": "#/$defs/BankTemplateConfig"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Bank configuration to apply. Omit to leave config unchanged."
|
|
},
|
|
"mental_models": {
|
|
"anyOf": [
|
|
{
|
|
"items": {
|
|
"$ref": "#/$defs/BankTemplateMentalModel"
|
|
},
|
|
"type": "array"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Mental models to create or update (matched by id). Omit to leave unchanged.",
|
|
"title": "Mental Models"
|
|
},
|
|
"directives": {
|
|
"anyOf": [
|
|
{
|
|
"items": {
|
|
"$ref": "#/$defs/BankTemplateDirective"
|
|
},
|
|
"type": "array"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"default": null,
|
|
"description": "Directives to create or update (matched by name). Omit to leave unchanged.",
|
|
"title": "Directives"
|
|
}
|
|
},
|
|
"required": [
|
|
"version"
|
|
],
|
|
"title": "BankTemplateManifest",
|
|
"type": "object"
|
|
}
|