This tutorial prepares one public test repository and its writable test store. Its single focus is the identity and scope foundation that every later coding-memory tutorial reuses.
Complete Tutorial 00: Connect your coding harness to Loom and Tutorial 02: Connect to multiple stores first.
loom_demo the session defaultloom_demo and make it the default for this session only. Confirm the effective session default, and do not edit ~/.loom/stores.toml.loom_demo store and changes only this session's default routing.loom_demo is now the default for this session. Persistent configuration was not changed.Continue in the public palmerpenguins repository that you checked out and opened as your coding harness's workspace in Tutorial 00. If that repository is not the current workspace, return to Tutorial 00: Connect your coding harness to Loom and complete its first step before continuing.
Repository scope and store selection solve different problems: the repository tells Loom which work the memory belongs to, while the store tells Loom where to read and write it. Verify both before creating facts so later sessions can retrieve them from the same boundary.
loom_demo. It reports the live store fields instead of assuming that recorded tutorial counts are still current.palmerpenguins/, bundled CSV files are under palmerpenguins/data/, and tests are under tests/. [loom_demo] is loaded as the writable tutorial store; its description confirms the coding domain and that the store is reachable.Before continuing, have the agent verify that the exact [loom_demo] alias exists and contains Project("loom_demo") plus the starter Roadmap and Decision used below. If the alias or seed is absent, reinstall the current Loom Cloud bundle and stop here. Do not use an unrelated [demo] or [tutorials] store just because its name looks close.
loom_demo for tutorial changes.loom_demo branch without changing a remote branch.loom_demo branch is ready. Git will record source changes; [loom_demo] will hold durable agent memory about the work.Loom attributes every fact to a real author so a shared store stays trustworthy across multiple developers. The author identity comes from git, not from you typing a name.
git config user.email and git config user.name, then checks whether a matching GitUser node already exists in [loom_demo].git config user.email returned dev1@gmail.com (name: Developer One). This masked address is sample output. In a real run, every save and edge below substitutes the exact value returned by this repository's git config user.email. On a first run, [loom_demo] may have no matching GitUser node yet; on a rerun it may already exist.Loom's substrate is resolve-or-reject: an edge can only point at a node that already exists, so the identity node must be created before any fact carries an Author() edge to it. Bootstrap it with a get-or-create save:
GitUser exists in [loom_demo] so my facts can be attributed to it — create it if it is missing.GitUser("<actual git config user.email>") in [loom_demo], substituting the value it just read rather than the masked sample. If the node already exists, the save is an idempotent no-op — Loom returns the same fact id back — so this step never duplicates on a rerun.GitUser("dev1@gmail.com") exists in [loom_demo] (created just now, or already present from an earlier run — either way it is the same node). In your run, both this node and every Author() edge use the actual email returned by git.Canonical deduplication does not merge new edges into an existing fact. If a tutorial fact already exists under another author, resaving its canonical returns the existing fact id and leaves its original Author() edge unchanged; report that history rather than claiming it was re-attributed.
If git config user.email is empty, points at a stale CI identity, or is otherwise not the identity you intend to use, fix it before saving anything — a wrong email silently forks a second author node that never matches your real history.
Facts are filed with InScope() edges to plain entity nodes, and those nodes are connected by PartOf edges into a chain: Repo -> Project -> Workspace -> Organization. Reads at a node automatically union up that chain — a repository-level read also sees project-, workspace-, and org-wide facts — so the chain has to actually exist, or reads from an ancestor come back empty even when the data is right there.
[loom_demo], ensure Repo("palmerpenguins") exists with PartOf() -> Project("palmerpenguins"), and ensure that project continues through Workspace("palmerpenguins") to Organization("loom-tutorials"). Verify the complete chain. Then add only loom-scope: project=palmerpenguins workspace=palmerpenguins org=loom-tutorials to existing root agent guidance. If this repository has none of AGENTS.md, CLAUDE.md, or CODEX.md, create root AGENTS.md containing only that line.PartOf() hops. For an existing node with a missing hop it uses the idempotent edge-add operation; resaving the canonical would not merge the edge. It verifies Repo("palmerpenguins") → Project("palmerpenguins") → Workspace("palmerpenguins") → Organization("loom-tutorials"). It preserves all existing guidance and adds only the one loom-scope line, creating root AGENTS.md only when no supported root guidance file exists.Repo("palmerpenguins") → Project("palmerpenguins") → Workspace("palmerpenguins") → Organization("loom-tutorials") (created or repaired on a first run; unchanged on a rerun). The supported root guidance now carries the same scope coordinates and no unrelated guidance changed.The resulting Entity/Relation shape is:
Repo("palmerpenguins")
PartOf → Project("palmerpenguins")
PartOf → Workspace("palmerpenguins")
PartOf → Organization("loom-tutorials")Repo, Project, Workspace, and Organization are Entity types: they describe what each node is. PartOf is a Relation type: it connects those different entities without changing their identities.
The loom-scope guidance closes the loop between stored scope and live sessions. Without it, a new agent may infer the repository name but miss the workspace and organization, reducing hook reads to repository-only context and hiding project-scoped facts.
PartOf edges are one-directional and the union-up direction only goes toward ancestors. Reading from Project("palmerpenguins") now also picks up anything scoped at the workspace or organization level — but reading from Organization("loom-tutorials") directly will not show facts scoped narrowly at the project below it. Ancestors see down into nothing; descendants see up the whole chain. Keep that direction straight: file a fact at the narrowest node that applies, and read from wherever you're currently working.
Before saving any project facts, ask for a bounded inventory of the whole store. This is more revealing than naming a few types in advance: it shows both the data you expected and anything you did not know was there, without letting a large type overwhelm the response.
The result should orient you, not act as a fixed snapshot. Counts grow as the tutorials add facts, while the concrete types and scope labels explain what each item means and where it applies.
[loom_demo], display up to 5 current items for every populated type in this Loom store.Decision (1):
- small reviewed tutorial changes before live deploys
Directive (2):
- ask before pushing origin main
- keep access bundles local
GitUser (1):
- dev1@gmail.com
Organization (1):
- loom-tutorials
Project (2):
- loom_demo
- palmerpenguins
Repo (1):
- palmerpenguins
Roadmap (1):
- publish runnable onboarding demo for new agents [active]
Workspace (1):
- palmerpenguinsRead this as "the inventory includes at least these" rather than an exact report: the counts and examples change as you work through this and later tutorials, and on a rerun you will also see the facts previous passes saved — extra Directives, a Finding, and PaidService entries from Tutorial 07, among others. That is expected, not pollution; this question is a quick store orientation, not a hard-coded report. On a fresh account it exposes exactly the seeded loom_demo starter facts alongside the identity and scope nodes you just created, in one bounded view. Only populated types appear; Tutorial 04 uses the type catalog to show declared types even when they have no facts yet.
This inventory is deliberately whole-store rather than project-scoped. The returned labels show that the seeded Directive, Decision, and Roadmap items are scoped to Project("loom_demo") — the demo store's own starter project — while the sample GitUser("dev1@gmail.com"), Repo("palmerpenguins"), and its project/workspace/organization ancestors are the identity and scope entities from §2–§3. Your real run substitutes its Git email. When you need only project-scoped coding facts, ask for that scope explicitly; identity and scope nodes do not themselves carry the same filing edge.
git config user.email, never from a typed-in name.Repo -> Project -> Workspace -> Organization chain.