Skip to content

Reflections & Knowledge ​

A Reflection is an Interaction that asks questions about other Interactions or Explorations. Its answers start as throwaway text; the useful ones get promoted into files that outlive the conversation.

The pipeline:

Exploration → Reflection → answer → classify → promote → a file in the repo

Status: this pipeline is a programmatic API. There is no top-level umwelten knowledge command — the closest CLI surface is umwelten sessions digest knowledge, which shows knowledge accumulated by digestion rather than driving promotion. Everything below is TypeScript.

Reflecting ​

buildReflectiveInteraction constructs an Interaction whose system prompt is a reflective analyst plus the context of the Explorations you're asking about. It is not a new runner — just a configured Interaction, so it streams, costs, and persists like any other.

typescript
import { buildReflectiveInteraction } from "@umwelten/core/interaction/reflection/reflection.js";

const interaction = buildReflectiveInteraction(
  explorations,
  "What did we decide about auth token refresh, and did it stick?",
  { model },
);
const response = await interaction.streamText();

To ask several questions at once over a live conversation instead of saved Explorations, use Turn Fan-out.

Promotion ​

An answer is worth keeping in different places depending on what kind of thing it is. classifyReflectionAnswer decides which:

typescript
import { classifyReflectionAnswer } from "@umwelten/core/interaction/promotion/classifier.js";
import { PromotionRouter } from "@umwelten/core/interaction/promotion/index.js";

const decision = classifyReflectionAnswer(response.content);
await new PromotionRouter(projectPath).promote(decision);

Eight targets, each with its own writer:

targetlands infor
agent-instructionAGENTS.md (CLAUDE.md for compatibility)imperative guidance to future agents
project-factFACTS.mddeclarative truths about the project
domain-languageCONTEXT.mda term and what to avoid calling it
adrdocs/adr/a decision that was hard to reverse
skilla Skill drafta repeatable procedure
artifact.umwelten/artifacts/YYYY-MM-DD-slug.exta dated output for humans
saved-reflection.umwelten/reflections/worth keeping, not yet worth promoting
user-model.umwelten/user-model.mdhow this person works

Choosing between them ​

The distinction that gets muddled most often:

  • FACTS.md is declarative — what is true. "The Gaia dashboard runs on 7420."
  • AGENTS.md is imperative — what to do. "Always run pnpm test:run, never pnpm test."

A gotcha goes in AGENTS.md if it implies future behaviour, in FACTS.md if it's a surprising truth, and into a Skill if it's a repeatable procedure.

saved-reflection is the holding area. Use it when an answer is clearly worth keeping but you don't yet know where it belongs — promoting too eagerly fills FACTS.md with things that turn out to be wrong.

Marker-managed sections ​

Writers that touch shared files insert into bounded regions rather than appending, so re-promotion updates in place instead of duplicating:

markdown
## Reflections
<!-- umwelten:reflections:start -->
...generated content...
<!-- umwelten:reflections:end -->

FACTS.md is the exception — freeform Markdown, not a machine section. Edit it by hand freely.

Skill candidates ​

A Skill Candidate is a possible procedure spotted during reflection or digest extraction but not yet promoted. Candidates live in .umwelten/candidates/; promoting one turns it into a Skill. The two-step exists because most candidates don't survive contact with a second use.

Explicit fact extraction ​

Separate from the promotion pipeline, packages/core/src/memory/ offers direct helpers for pulling facts out of a conversation and reconciling them against a store you manage:

typescript
import { extractFacts } from "@umwelten/core/memory/extract_facts.js";
import { determineOperations } from "@umwelten/core/memory/determine_operations.js";

const facts = await extractFacts(interaction, modelDetails);
const ops = await determineOperations(modelDetails, facts, existingMemories);
// ops: ADD / UPDATE / NONE against a caller-managed store

There is no automatic chat memory. Interaction always uses the base runner; memory is something you do deliberately, not a runner mode.

For the per-session equivalent — append-only typed learnings under a habitat session directory — see Source Sessions.

Where things live ​

AGENTS.md                      # imperative guidance (CLAUDE.md for compat)
FACTS.md                       # declarative project truths
CONTEXT.md                     # domain language
docs/adr/                      # decisions
.umwelten/
  reflections/                 # saved answers, dated
  artifacts/                   # YYYY-MM-DD-slug.ext
  candidates/                  # skill candidates
  explorations/                # saved exploration manifests
  user-model.md                # how this person works

Everything project-local is human-readable and hand-editable by design. If a promotion writes something wrong, fix the file.

Released under the MIT License.