FishMem

Give a coding agent project memory

Store architecture decisions, conventions, and gotchas so a coding agent stops re-learning the codebase every session.

A coding agent starts every session from zero. It re-reads the codebase, re-derives the naming conventions, and rediscovers the same gotchas it hit last week. None of that work carries over, so each session pays the same ramp-up cost.

Give it project memory instead. Store the decisions and conventions once, scoped to the agent and the project, and recall the relevant ones before generating code.

Scope by agent and project

Use two scopes together:

  • agent_id identifies the coding agent.
  • run_id identifies the repo or project the memory belongs to.

This keeps the agent's knowledge of one project isolated from another. See scoping for how the scopes compose on reads and writes.

Store decisions, conventions, and gotchas

Two kinds of facts go in, and they want different infer settings:

  • Verbatim rules — naming conventions, lint rules, "always do X" directives. Store these with infer: false so they land exactly as written, with no extraction or rewording.
  • Extracted facts — knowledge that emerges from a design discussion. Store the conversation with infer: true and let FishMem pull out the durable facts.
seed-project-memory.ts
import { FishMem } from 'fishmem';

const client = new FishMem({ apiKey: process.env.FISHMEM_API_KEY });

const scope = { agent_id: 'agent_codegen', run_id: 'repo_billing-service' };

// Verbatim rule — store exactly as written.
await client.add('All API handlers live in src/handlers and export a default async function.', {
  ...scope,
  infer: false,
  metadata: { kind: 'convention' },
});

// Extracted facts from a design discussion.
await client.add(
  [
    { role: 'user', content: 'We moved off Prisma to raw SQL via the pg driver because of cold-start latency.' },
    { role: 'assistant', content: 'Understood — queries now go through the db/query helper.' },
  ],
  { ...scope, infer: true, metadata: { kind: 'architecture' } }
);

Recall before generating code

Before the agent writes code, search the project's memories for conventions and decisions that bear on the task, then inject them into the prompt.

generate-with-memory.ts
import { FishMem } from 'fishmem';
import { llm } from './llm'; // your model call

const client = new FishMem({ apiKey: process.env.FISHMEM_API_KEY });

async function generate(task: string) {
  const { results } = await client.search(task, {
    agent_id: 'agent_codegen',
    run_id: 'repo_billing-service',
    top_k: 8,
  });

  const conventions = results.map((m) => `- ${m.memory}`).join('\n');

  const system = [
    'You are a coding agent for the billing-service repo.',
    'Follow these established conventions and decisions exactly:',
    conventions || '(none recorded yet)',
  ].join('\n');

  return llm({ system, user: task });
}

When to use infer: false

Reach for infer: false whenever the wording itself is load-bearing — a path, a lint rule, an exact directive. Inference is designed to extract and reconcile facts; for a rule like "handlers export a default async function," extraction would only risk paraphrasing it. Raw mode also costs 1 credit instead of 2. Use infer: true for prose, design discussions, and anything where you want FishMem to find the durable fact for you.

On this page