standards
Skills and memoriesCookbooks

Skills and memories

Teach the workspace agent a skill and give it a memory about one of your records, using nothing but the records API every object already has.


Every workspace ships with two native objects, skill and memory. The agent reads skills to know how to do a task and memories to know what it learned about your data. Both are ordinary records: the same REST routes, filters, search, views, permissions and MCP tools your own objects get apply to them. This cookbook creates one of each from the SDK and shows the agent using them.

What you will build

A skill named invoice-followup that the agent follows the next time someone asks it to chase a payment, and a memory attached to one of your companies records that the agent finds when that company comes up. You verify both from the SDK, the CLI, the search endpoint and the app.

What a skill is

A skill is three attributes and, optionally, attached files:

AttributeTypeLimitWhat the agent does with it
nametext, required100 charactersThe handle it calls get_skill with.
descriptiontext, required160 charactersOne line in its prompt: what the skill does and when to use it. It reads every description, so this line decides whether the skill is picked.
contentrichtextThe instructions it reads once it has picked the skill. Written for the agent, not for people.

New skills start from a template with the sections ## Overview, ## When to use, ## Instructions, ## Examples and ## What to avoid. Files attached to a skill travel with it: a reference PDF or a CSV template is copied next to the agent when it loads the skill.

What a memory is

A memory is a note the agent keeps across conversations, with a lifecycle:

AttributeTypeValues
name, description, contenttext, text, richtextSame limits as a skill.
kindselectfact, preference, feedback, reference
subjectsrelation to any object, manyThe records this memory is about.
sourceselectexplicit is what save_memory writes. extracted, corroborated and curated are written by the workspace's own extraction and nightly consolidation. Nothing sets it for you over REST or the SDK: pass source: "explicit" yourself, as the samples do, or it stays empty.
validFrom, invalidAt, supersededBydate with time, date with time, relation to memoryA memory is never deleted by the agent: it is invalidated or superseded, and the history stays.
reviewState, reviewReasonselect, textneeds_review or skill_candidate. A memory in review is kept from the agent until cleared.

A few more attributes (links, provenance, the curation timestamps) are maintained by the workspace; you can read them and leave them alone.

There is no owner attribute. A memory is workspace or private like any record, and a private one is visible only to the actor that created it.

Prerequisites

  • A workspace, an API key whose role reads and writes skill, memory and your own objects, and @stndrds/client installed.
  • One record of your own to attach the memory to. The steps use a companies record named Acme; any object works.

Look at the native objects

They are already there; nothing to sync. The sealed flag means their attributes are owned by Standards.

standards schema inspect skill
standards schema inspect memory

Through MCP, get_schema with objectNames: ["skill", "memory"] returns the same definition in one call.

Do not declare an object named skill, memory, drives, artifact or meeting: object() throws ReservedObjectNameError at declaration, and a schema source that carries one is refused. Do not add attributes to them either; standards diff flags every attribute a sealed object did not declare as UNEXPECTED (sealed).

Create a skill

The client has no typed builder for native objects, so use the object's name. The description is the line the agent reads to decide; make it say what and when.

import { getStandards } from "./client";

const skills = getStandards().from("skill");

await skills.create({
  name: "invoice-followup",
  description: "Drafts a polite reminder for an overdue invoice. Use when asked to chase a payment.",
  content: [
    "## Overview",
    "Write a short, courteous reminder for an invoice that is past its due date.",
    "",
    "## When to use",
    "- When asked to chase, follow up on or remind about a payment.",
    "",
    "## Instructions",
    "1. Read the invoice record: number, amount, due date, contact.",
    "2. Write three sentences: the invoice, the amount and date, one clear ask.",
    "3. Sign with the sender's first name only.",
    "",
    "## What to avoid",
    "- Never threaten fees or legal action.",
  ].join("\n"),
});

Names are unique on purpose: the four built-in skills (document-generation, agent-browser, ui, skill-creator) keep their names, and a record that reuses one is ignored.

Watch the agent use it

Open a conversation in the app and ask: "Chase the payment on invoice 2026-041." The agent's prompt lists up to 40 skills by description, the four built-ins first; it calls get_skill with the name, then follows the content. The call shows in the run, with the skill's name. No restart, no registration: the skill is read fresh on the next turn.

Give the agent a memory about a record

Attach the memory to the Acme record through subjects, so it surfaces whenever Acme is mentioned.

const companies = getStandards().from("companies");
const memories = getStandards().from("memory");

const acme = await companies.eq("name", "Acme").single();
if (!acme) throw new Error("create the Acme company first");

await memories.create({
  name: "acme-prefers-french",
  description: "Acme wants every message in French, addressed to Claire Morel.",
  kind: "preference",
  source: "explicit",
  subjects: [acme.id],
});

A record created this way is visible to the whole workspace. For a memory only you can see, create it over REST with the visibility option:

curl -X POST https://api.standards.new/v1/records/memory \
  -H "Authorization: Bearer $STANDARDS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "data": { "name": "my-note-on-acme", "description": "Call after 14:00.", "kind": "fact", "source": "explicit" },
    "options": { "visibility": "private" }
  }'

Find it back, four ways

The memory is a record, so every read path works. From the SDK, filter on the relation:

const about = await memories.in("subjects", [acme.id]).fetch();
about.records.map((memory) => memory.name); // ["acme-prefers-french"]

From the CLI, full-text search on the object:

standards records search memory --query french --format table

From the workspace-wide search, restricted to the two native objects:

curl "https://api.standards.new/v1/search?q=french&objects=memory,skill" \
  -H "Authorization: Bearer $STANDARDS_API_KEY"

From the agent: @-mention the Acme record in a message (up to five records per turn count). The prompt gains a ## Memories about the records mentioned section listing each attached memory's name: description, and the agent opens one with get_memory before using it. Every live memory is also listed in the ## Memories index, up to 40, ranked by relevance to your message when there are more, attached ones first; past that the agent calls search_memories.

See both in the app

The sidebar lists Skills and Memories with the other intelligence objects. Skills open on their content with a Files tab, where you attach the reference PDF the skill mentions. Memories have four tabs: Memories, My memories, To review and History. Everything you create here is the same record you created from the SDK.

What the agent adds on its own

When it saves a memory itself, the agent calls save_memory, which first searches for close matches. If it finds any it saves nothing and returns the candidates; the agent then re-calls with updateMemoryId to update one, or force: true to create anyway. After a conversation, the workspace extracts new memories as private records, some flagged for review, with source: "extracted"; a nightly pass promotes the ones several people agree on and writes source: "corroborated" or curated. You never have to run any of that. As long as your own writes set source, the attribute tells what was saved by hand from what the workspace learned.

What you cannot do

  • Change or delete the native objects' attributes, or name your own object after one of them.
  • Exceed 100 characters on name or 160 on description; the API answers SCHEMA_VALIDATION_FAILED.
  • Call save_memory, search_memories, get_memory or get_skill over MCP: they are agent-only tools and never appear in tools/list. Over MCP, read and write the two objects with search_records, get_record, create_record and update_record like any object.
  • Set a memory's owner: ownership comes from the key that created it.

Next steps

  • Records: every filter used above, including in on a relation.
  • Objects and records: visibility, workspace versus private.
  • Tools: what an MCP client can do with skill and memory.
  • Agent workflow: the same objects from Claude Code.