@semantic-namespace/atlas
v0.1.0-alpha
Published
Atlas semantic registry for JavaScript — query, analyze, and reason about software architecture
Maintainers
Readme
Atlas JS — Semantic Registry for JavaScript
Atlas JS compiles the Atlas Clojure(Script) library to an ES module. Load an EDN registry snapshot or define entities from scratch, then query, analyze, and reason about your software architecture — all locally in the browser or Node.js.
No server required. The same .cljc source that runs on the JVM is compiled to JS. Every function behaves identically in both runtimes.
Two Builds
| Build | Bundle | Gzipped | Includes |
|-------|--------|---------|----------|
| Full (dist/atlas.js) | 546 KB | 125 KB | Registry + Query + Datalog + Invariants |
| Slim (dist-slim/atlas.js) | 291 KB | 72 KB | Registry + Query + Ontology (no Datascript) |
Use slim when you only need registration, querying, and analytics. Use full when you also need datalog graph traversal (upstream/downstream closure, blast radius).
Install & Build
cd js/
npm install
npm run build # full → dist/atlas.js
npm run build:slim # slim → dist-slim/atlas.js
npm run build:all # both
npm run dev # full, watch mode (source maps)
npm run dev:slim # slim, watch mode (source maps)
npm run cleanQuick Start — Load an EDN Snapshot
import { loadRegistry, summary, findByAspect } from "./dist/atlas.js";
// or: from "./dist-slim/atlas.js" (same API, minus datalog)
// Node.js
import { readFileSync } from "fs";
const edn = readFileSync("my-registry.edn", "utf-8");
// Browser
// const edn = await fetch("/registries/my-registry.edn").then(r => r.text());
const count = loadRegistry(edn);
console.log(`Loaded ${count} entities`);
console.log(summary());
// => { total: 489, "unique-aspects": 269, ... }
const auth = findByAspect("domain/auth");
// => { "#{...}": { "atlas/dev-id": "fn/validate-token", ... }, ... }Exporting from CLJ
From a running Clojure REPL:
(spit "my-registry.edn" (pr-str @atlas.registry/registry))Or fetch from the Atlas UI server:
const edn = await fetch("http://localhost:8082/api/atlas/registry").then(r => r.text());
loadRegistry(edn);Quick Start — Define Entities from JS
You can build a full registry from scratch without any EDN file.
import { resetRegistry, register, findByAspect, summary } from "./dist/atlas.js";
resetRegistry();
// Structure component (infrastructure)
register("component/postgres", "atlas/structure-component",
["domain/persistence", "tier/foundation", "protocol/sql"],
{ "structure-component/deps": [] }
);
// Execution function (business logic)
register("fn/authenticate-user", "atlas/execution-function",
["domain/auth", "tier/service", "operation/validate"],
{
"execution-function/context": ["auth/email", "auth/password"],
"execution-function/response": ["auth/session-token", "auth/user-id"],
"execution-function/deps": ["component/postgres"]
}
);
// Interface endpoint (API layer)
register("endpoint/login", "atlas/interface-endpoint",
["domain/auth", "tier/api"],
{
"interface-endpoint/context": ["auth/email", "auth/password"],
"interface-endpoint/response": ["auth/session-token"],
"interface-endpoint/deps": ["fn/authenticate-user"]
}
);
console.log(summary());
// => { total: 3, "unique-aspects": 7, ... }Full Example — Calendar App
This example defines a complete calendar application with 18 entities across 3 tiers.
import {
resetRegistry, register,
findByAspect, findByDevId, findDevIdsWithAspect,
where, semanticSimilarity, queryAlgebra,
aspectFrequency, relatedAspects,
byTier, dependencyGraph, domainCoupling, impactOfChange,
traceDataFlow, summary
} from "./dist/atlas.js";
resetRegistry();
// ═══════════════════════════════════════════════════════════════════
// TIER: FOUNDATION — Infrastructure components
// ═══════════════════════════════════════════════════════════════════
register("component/postgres", "atlas/structure-component",
["domain/persistence", "tier/foundation", "protocol/sql"],
{ "structure-component/deps": [] }
);
register("component/redis", "atlas/structure-component",
["domain/cache", "tier/foundation", "protocol/redis"],
{ "structure-component/deps": [] }
);
register("component/google-oauth", "atlas/structure-component",
["domain/auth", "tier/foundation", "protocol/oauth", "integration/external"],
{ "structure-component/deps": [] }
);
register("component/google-calendar", "atlas/structure-component",
["domain/calendar", "tier/foundation", "protocol/rest", "integration/external"],
{ "structure-component/deps": [] }
);
register("component/smtp", "atlas/structure-component",
["domain/notifications", "tier/foundation", "protocol/smtp", "integration/external"],
{ "structure-component/deps": [] }
);
// ═══════════════════════════════════════════════════════════════════
// TIER: SERVICE — Business logic functions
// ═══════════════════════════════════════════════════════════════════
register("fn/authenticate-user", "atlas/execution-function",
["domain/auth", "tier/service", "operation/validate"],
{
"execution-function/context": ["auth/email", "auth/password"],
"execution-function/response": ["auth/session-token", "auth/user-id"],
"execution-function/deps": ["component/postgres", "component/google-oauth"]
}
);
register("fn/refresh-oauth-token", "atlas/execution-function",
["domain/auth", "tier/service", "operation/refresh"],
{
"execution-function/context": ["auth/user-id"],
"execution-function/response": ["auth/oauth-token"],
"execution-function/deps": ["component/google-oauth", "component/redis"]
}
);
register("fn/list-calendars", "atlas/execution-function",
["domain/calendar", "tier/service", "operation/read", "scope/collection"],
{
"execution-function/context": ["auth/user-id", "auth/oauth-token"],
"execution-function/response": ["calendar/list"],
"execution-function/deps": ["component/google-calendar"]
}
);
register("fn/fetch-events", "atlas/execution-function",
["domain/calendar", "tier/service", "operation/read", "scope/detail"],
{
"execution-function/context": ["calendar/id", "calendar/date-range"],
"execution-function/response": ["calendar/events"],
"execution-function/deps": ["component/google-calendar", "component/redis"]
}
);
register("fn/create-event", "atlas/execution-function",
["domain/calendar", "tier/service", "operation/write", "effect/write"],
{
"execution-function/context": ["calendar/id", "calendar/event-data"],
"execution-function/response": ["calendar/event-id"],
"execution-function/deps": ["component/google-calendar"]
}
);
register("fn/check-availability", "atlas/execution-function",
["domain/calendar", "domain/scheduling", "tier/service", "operation/read"],
{
"execution-function/context": ["calendar/user-ids", "calendar/date-range"],
"execution-function/response": ["scheduling/available-slots"],
"execution-function/deps": ["component/google-calendar", "component/redis"]
}
);
register("fn/send-invite", "atlas/execution-function",
["domain/notifications", "domain/scheduling", "tier/service", "effect/write"],
{
"execution-function/context": ["scheduling/event-id", "scheduling/invitees"],
"execution-function/response": ["notification/sent-count"],
"execution-function/deps": ["component/smtp", "component/postgres"]
}
);
register("fn/cache-events", "atlas/execution-function",
["domain/cache", "domain/calendar", "tier/service", "operation/write"],
{
"execution-function/context": ["calendar/events", "auth/user-id"],
"execution-function/response": ["cache/stored"],
"execution-function/deps": ["component/redis"]
}
);
// ═══════════════════════════════════════════════════════════════════
// TIER: API — Interface endpoints
// ═══════════════════════════════════════════════════════════════════
register("endpoint/login", "atlas/interface-endpoint",
["domain/auth", "tier/api"],
{
"interface-endpoint/context": ["auth/email", "auth/password"],
"interface-endpoint/response": ["auth/session-token"],
"interface-endpoint/deps": ["fn/authenticate-user"]
}
);
register("endpoint/calendars", "atlas/interface-endpoint",
["domain/calendar", "tier/api", "operation/read", "scope/collection"],
{
"interface-endpoint/context": ["auth/session-token"],
"interface-endpoint/response": ["calendar/list"],
"interface-endpoint/deps": ["fn/refresh-oauth-token", "fn/list-calendars"]
}
);
register("endpoint/events", "atlas/interface-endpoint",
["domain/calendar", "tier/api", "operation/read", "scope/detail"],
{
"interface-endpoint/context": ["auth/session-token", "calendar/id", "calendar/date-range"],
"interface-endpoint/response": ["calendar/events"],
"interface-endpoint/deps": ["fn/refresh-oauth-token", "fn/fetch-events", "fn/cache-events"]
}
);
register("endpoint/create-event", "atlas/interface-endpoint",
["domain/calendar", "tier/api", "operation/write", "effect/write"],
{
"interface-endpoint/context": ["auth/session-token", "calendar/id", "calendar/event-data"],
"interface-endpoint/response": ["calendar/event-id"],
"interface-endpoint/deps": ["fn/refresh-oauth-token", "fn/create-event"]
}
);
register("endpoint/schedule-meeting", "atlas/interface-endpoint",
["domain/scheduling", "tier/api", "operation/write", "effect/write"],
{
"interface-endpoint/context": ["auth/session-token", "calendar/user-ids",
"calendar/date-range", "calendar/event-data"],
"interface-endpoint/response": ["calendar/event-id", "notification/sent-count"],
"interface-endpoint/deps": ["fn/check-availability", "fn/create-event", "fn/send-invite"]
}
);
// Data schemas
register("schema/user", "atlas/data-schema",
["domain/auth"],
{ "data-schema/fields": ["auth/user-id", "auth/email", "auth/oauth-token"] }
);
register("schema/calendar-event", "atlas/data-schema",
["domain/calendar"],
{ "data-schema/fields": ["calendar/event-id", "calendar/id",
"calendar/event-data", "calendar/date-range"] }
);
// ═══════════════════════════════════════════════════════════════════
// QUERYING — Everything below works on the registry we just built
// ═══════════════════════════════════════════════════════════════════
console.log("=== summary() ===");
console.log(summary());
// { total: 20, "unique-aspects": 26, ... }
// ─── findByAspect ──────────────────────────────────────────────────
console.log("\n=== findByAspect('domain/auth') ===");
const auth = findByAspect("domain/auth");
Object.values(auth).forEach(v => console.log(" ", v["atlas/dev-id"]));
// component/google-oauth, fn/authenticate-user, fn/refresh-oauth-token,
// endpoint/login, schema/user
console.log("\n=== findByAspect(['domain/calendar', 'tier/service']) ===");
const calSvc = findByAspect(["domain/calendar", "tier/service"]);
Object.values(calSvc).forEach(v => console.log(" ", v["atlas/dev-id"]));
// fn/list-calendars, fn/fetch-events, fn/create-event,
// fn/check-availability, fn/cache-events
// (5 functions — all calendar-related service tier)
// ─── findByDevId ───────────────────────────────────────────────────
console.log("\n=== findByDevId('fn/authenticate-user') ===");
const [compoundId, entity] = findByDevId("fn/authenticate-user");
console.log("compound-id:", compoundId);
// ["domain/auth", "operation/validate", "tier/service", "atlas/execution-function"]
console.log("context:", entity["execution-function/context"]);
// ["auth/email", "auth/password"]
console.log("response:", entity["execution-function/response"]);
// ["auth/session-token", "auth/user-id"]
console.log("deps:", entity["execution-function/deps"]);
// ["component/postgres", "component/google-oauth"]
// ─── findDevIdsWithAspect ──────────────────────────────────────────
console.log("\n=== findDevIdsWithAspect('effect/write') ===");
console.log(findDevIdsWithAspect("effect/write"));
// ["fn/create-event", "fn/send-invite", "endpoint/create-event",
// "endpoint/schedule-meeting"]
// ─── where (predicate filtering) ──────────────────────────────────
console.log("\n=== where: functions with >1 dependency ===");
const multiDep = where((id, val) => {
const deps = val["execution-function/deps"];
return deps && deps.length > 1;
});
Object.values(multiDep).forEach(v =>
console.log(" ", v["atlas/dev-id"], "→", v["execution-function/deps"])
);
// fn/authenticate-user → [component/postgres, component/google-oauth]
// fn/refresh-oauth-token → [component/google-oauth, component/redis]
// fn/check-availability → [component/google-calendar, component/redis]
// fn/fetch-events → [component/google-calendar, component/redis]
// fn/send-invite → [component/smtp, component/postgres]
console.log("\n=== where: entities touching external integrations ===");
const external = where((id, val) => id.includes("integration/external"));
Object.values(external).forEach(v => console.log(" ", v["atlas/dev-id"]));
// component/google-oauth, component/google-calendar, component/smtp
// ─── semanticSimilarity ───────────────────────────────────────────
console.log("\n=== semanticSimilarity of endpoint/schedule-meeting ===");
const schedId = findByDevId("endpoint/schedule-meeting")[0];
const similar = semanticSimilarity(schedId, 0.3);
similar.forEach(s =>
console.log(
" sim=" + s.similarity.toFixed(2),
"shared:", s.shared.join(", ")
)
);
// sim=0.67 shared: tier/api, operation/write, effect/write, atlas/interface-endpoint
// sim=0.33 shared: tier/api, atlas/interface-endpoint
// ─── aspectFrequency ──────────────────────────────────────────────
console.log("\n=== aspectFrequency() ===");
const freq = aspectFrequency();
Object.entries(freq).forEach(([k, v]) => console.log(` ${k} = ${v}`));
// domain/calendar = 8, tier/service = 7, atlas/execution-function = 7,
// domain/auth = 5, tier/foundation = 5, ...
// ─── relatedAspects ───────────────────────────────────────────────
console.log("\n=== relatedAspects('domain/calendar') ===");
const rel = relatedAspects("domain/calendar");
Object.entries(rel).forEach(([k, v]) => console.log(` ${k} = ${v}`));
// tier/service = 4, operation/read = 3, operation/write = 3,
// effect/write = 2, tier/api = 2, ...
// ─── byTier ───────────────────────────────────────────────────────
console.log("\n=== byTier('atlas/dev-id') ===");
const tiers = byTier("atlas/dev-id");
Object.entries(tiers).forEach(([tier, devIds]) =>
console.log(` ${tier}: ${devIds.join(", ")}`)
);
// tier/foundation: component/redis, component/postgres, ... (5)
// tier/service: fn/authenticate-user, fn/refresh-oauth-token, ... (8)
// tier/api: endpoint/login, endpoint/calendars, ... (5)
// ─── dependencyGraph ──────────────────────────────────────────────
console.log("\n=== dependencyGraph('atlas/dev-id', 'execution-function/deps') ===");
const graph = dependencyGraph("atlas/dev-id", "execution-function/deps");
graph.forEach(g => console.log(` ${g.id} → ${JSON.stringify(g.deps)}`));
// fn/authenticate-user → ["component/postgres","component/google-oauth"]
// fn/refresh-oauth-token → ["component/google-oauth","component/redis"]
// fn/list-calendars → ["component/google-calendar"]
// fn/fetch-events → ["component/google-calendar","component/redis"]
// fn/create-event → ["component/google-calendar"]
// fn/check-availability → ["component/google-calendar","component/redis"]
// fn/send-invite → ["component/smtp","component/postgres"]
// fn/cache-events → ["component/redis"]
// ─── impactOfChange ──────────────────────────────────────────────
console.log("\n=== impactOfChange('fn/refresh-oauth-token') ===");
const impact = impactOfChange(
"fn/refresh-oauth-token",
"atlas/dev-id",
"interface-endpoint/deps",
"execution-function/response"
);
console.log("produces:", impact["entity/produces"]);
// ["auth/oauth-token"]
console.log("dependents:", impact["direct-dependents"]);
// ["endpoint/calendars", "endpoint/events", "endpoint/create-event"]
// ─── traceDataFlow ───────────────────────────────────────────────
console.log("\n=== traceDataFlow('auth/session-token') ===");
const flow = traceDataFlow(
"auth/session-token",
"execution-function/response",
"interface-endpoint/context"
);
console.log("producers:", Object.values(flow.producers).map(v => v["atlas/dev-id"]));
// ["fn/authenticate-user"]
console.log("consumers:", Object.values(flow.consumers).map(v => v["atlas/dev-id"]));
// ["endpoint/calendars", "endpoint/events", "endpoint/create-event",
// "endpoint/schedule-meeting"]
console.log("connected:", flow["connected?"]);
// true
// ─── queryAlgebra ────────────────────────────────────────────────
console.log("\n=== queryAlgebra: calendar ∩ write ===");
const inter = queryAlgebra({
intersection: [["domain/calendar"], ["effect/write"]]
});
console.log("count:", inter.length);
// 2 (fn/create-event, endpoint/create-event)
console.log("\n=== queryAlgebra: service \\ write (read-only services) ===");
const readOnly = queryAlgebra({
difference: [["tier/service"], ["effect/write"]]
});
console.log("count:", readOnly.length);
// 5 (fn/authenticate-user, fn/refresh-oauth-token, fn/list-calendars,
// fn/fetch-events, fn/check-availability)API Reference
Convention: Qualified Keywords as Strings
Atlas uses Clojure's qualified keywords (:namespace/name) as the fundamental identifier. In JS, these become strings with the same "namespace/name" format:
| Clojure | JavaScript |
|---------|-----------|
| :domain/auth | "domain/auth" |
| :atlas/execution-function | "atlas/execution-function" |
| #{:domain/auth :tier/service} | ["domain/auth", "tier/service"] |
| {:atlas/dev-id :fn/foo} | { "atlas/dev-id": "fn/foo" } |
Registry Lifecycle
| Function | Signature | Description |
|----------|-----------|-------------|
| loadRegistry | (ednString) → count | Parse EDN string, replace registry, return entity count |
| getRegistry | () → object | Return entire registry as JS object |
| resetRegistry | () → null | Clear the registry |
| register | (devId, type, aspects, value) → compoundId | Register with explicit dev-id |
| register | (type, aspects, value) → compoundId | Register with auto-generated dev-id |
register Parameters
| Parameter | Type | Example |
|-----------|------|---------|
| devId | string | "fn/validate-token" |
| type | string | "atlas/execution-function" |
| aspects | string[] | ["domain/auth", "tier/service"] |
| value | object | { "execution-function/context": ["auth/token"] } |
Returns the compound identity (as an array of strings).
Query Functions
| Function | Signature | Description |
|----------|-----------|-------------|
| findByAspect | (aspect) → {compoundId: entity} | Find entities containing aspect(s). Pass a string for single, array for AND. |
| findByDevId | (devId) → [compoundId, entity] | Lookup by dev-id. Returns null if not found. |
| findDevIdsWithAspect | (aspect) → string[] | All dev-ids containing the aspect. |
| findExact | (identityArray) → entity | Exact compound identity match. |
| where | (predFn) → {compoundId: entity} | Filter by predicate (compoundIdArray, valueObject) → boolean. |
| allIdentities | () → string[][] | All compound identities as array of arrays. |
Scoring & Matching
| Function | Signature | Description |
|----------|-----------|-------------|
| matchScore | (identity, aspects, mode) → number | Score 0.0-1.0. Mode: "and", "or", "count". |
| queryMatches | (identity, queryMap) → boolean | Match with selected, negated, mode, "min-score". |
| semanticSimilarity | (identity, minSim?) → [{identity, shared, similarity}] | Jaccard similarity, sorted descending. |
Analytics
| Function | Signature | Description |
|----------|-----------|-------------|
| aspectFrequency | () → {aspect: count} | How often each aspect appears across all entities. |
| relatedAspects | (aspect) → {aspect: count} | Aspects that co-occur with the given aspect. |
| identityStats | () → [{identity, size, value}] | All identities sorted by size descending. |
Architecture Analysis
| Function | Signature | Description |
|----------|-----------|-------------|
| dependencyGraph | (idKey, depsKey) → [{id, deps, identity}] | Build dependency graph from a property key. |
| byTier | (idKey) → {tier: devIds[]} | Group entities by tier/* aspect. |
| domainCoupling | (idKey, depsKey) → [{domain, "depends-on", "entity-count"}] | Cross-domain dependency analysis. |
| impactOfChange | (entityId, idKey, depsKey, responseKey) → {entity, "entity/produces", "direct-dependents"} | What breaks if this entity changes. |
The idKey and depsKey parameters tell Atlas which properties to use:
// For execution functions:
dependencyGraph("atlas/dev-id", "execution-function/deps");
// For interface endpoints:
dependencyGraph("atlas/dev-id", "interface-endpoint/deps");
// impactOfChange — who lists this entity in their deps?
impactOfChange("fn/refresh-oauth-token",
"atlas/dev-id", // which property holds the entity id
"interface-endpoint/deps", // which property holds dependency lists
"execution-function/response" // which property holds outputs
);Data Flow
| Function | Signature | Description |
|----------|-----------|-------------|
| findProducers | (dataKey, propertyKey) → {compoundId: entity} | Entities whose propertyKey contains dataKey. |
| findConsumers | (dataKey, propertyKey) → {compoundId: entity} | Same, for consumers. |
| traceDataFlow | (dataKey, producerKey, consumerKey) → {producers, consumers, "connected?"} | Full trace for a data key. |
// Who produces auth/session-token? (it's in their response)
findProducers("auth/session-token", "execution-function/response");
// Who consumes it? (it's in their context)
findConsumers("auth/session-token", "interface-endpoint/context");
// Full trace
traceDataFlow("auth/session-token",
"execution-function/response", // producer property
"interface-endpoint/context" // consumer property
);Set Algebra
| Function | Signature | Description |
|----------|-----------|-------------|
| queryAlgebra | ({intersection, union, or difference}) → compoundId[][] | Set operations on compound identities. |
// Entities in BOTH domain/calendar AND effect/write
queryAlgebra({ intersection: [["domain/calendar"], ["effect/write"]] });
// Entities in domain/calendar OR domain/auth
queryAlgebra({ union: [["domain/calendar"], ["domain/auth"]] });
// Entities in tier/service but NOT effect/write (read-only services)
queryAlgebra({ difference: [["tier/service"], ["effect/write"]] });Registry Introspection
| Function | Signature | Description |
|----------|-----------|-------------|
| registeredTypes | () → string[] | All registered entity types. |
| entityType | (identity) → string | Extract the entity type from a compound identity. |
| aspects | (identity) → string[] | Extract non-type aspects from a compound identity. |
| summary | () → object | Registry stats: total, unique aspects, top aspects, largest identities. |
| validateTypes | () → {valid, "registered-types"} | Check all entities use known types. |
Ontology
| Function | Signature | Description |
|----------|-----------|-------------|
| allOntologies | () → {compoundId: ontology} | All registered ontologies. |
| ontologyFor | (entityType) → object | Ontology definition for an entity type. |
Invariants (full build only)
| Function | Signature | Description |
|----------|-----------|-------------|
| checkInvariants | () → {valid, violations} | Run all registered invariant checks. |
Datalog Queries (full build only)
Datascript runs in the browser. These functions query a datalog database built from the registry. Call rebuildDatalog() after loading or modifying the registry.
| Function | Signature | Description |
|----------|-----------|-------------|
| rebuildDatalog | () → null | Rebuild the datalog DB (cached after first call). |
| queryEntitiesWithAspect | (aspect) → string[] | Find dev-ids by aspect via datalog. |
| queryDependencies | (devId) → string[] | Direct dependencies. |
| queryReverseDependencies | (devId) → string[] | Who depends on this entity. |
| queryUpstreamClosure | (devIdOrArray, maxHops) → [{entity, hops}] | Transitive dependencies with hop count. |
| queryDownstreamClosure | (devIdOrArray, maxHops) → [{entity, hops}] | Transitive dependents with hop count. |
| queryProducersOf | (dataKey) → string[] | Entities producing a data key (via datalog). |
| queryConsumersOf | (dataKey) → string[] | Entities consuming a data key (via datalog). |
Note: Datalog dependency/data-flow queries require extractors registered in the registry (
:atlas/datalog-extractorentities). Without extractors, the datalog DB only contains aspect facts. The set-based query functions (dependencyGraph,traceDataFlow,impactOfChange) read properties directly and always work.
Conversion Helpers
| Function | Signature | Description |
|----------|-----------|-------------|
| toJS | (cljData) → jsData | Keywords → strings, sets → arrays, maps → objects. |
| toClj | (jsData) → cljData | Strings with "/" → keywords. |
Entity Types
Atlas has built-in entity types, each with its own set of property keys:
atlas/execution-function — Business logic
register("fn/validate-token", "atlas/execution-function",
["domain/auth", "tier/service", "operation/validate"],
{
"execution-function/context": ["auth/token"], // inputs
"execution-function/response": ["auth/valid?"], // outputs
"execution-function/deps": ["component/oauth"] // infrastructure deps
}
);atlas/structure-component — Infrastructure
register("component/postgres", "atlas/structure-component",
["domain/persistence", "tier/foundation", "protocol/sql"],
{
"structure-component/deps": []
}
);atlas/interface-endpoint — API endpoints
register("endpoint/login", "atlas/interface-endpoint",
["domain/auth", "tier/api"],
{
"interface-endpoint/context": ["auth/email", "auth/password"], // request inputs
"interface-endpoint/response": ["auth/session-token"], // response outputs
"interface-endpoint/deps": ["fn/authenticate-user"] // functions called
}
);atlas/data-schema — Data structures
register("schema/user", "atlas/data-schema",
["domain/auth"],
{
"data-schema/fields": ["auth/user-id", "auth/email"]
}
);Custom entity types
You can register any entity type — just use a qualified "namespace/name" string:
register("flow/checkout", "myapp/user-flow",
["domain/cart", "domain/payment"],
{
"user-flow/steps": ["cart/review", "payment/enter", "payment/confirm"],
"user-flow/happy-path": true
}
);Common Aspect Namespaces
Aspects are the reusable semantic tags that form compound identities. Common namespaces:
| Namespace | Purpose | Examples |
|-----------|---------|---------|
| domain/* | Business domain | domain/auth, domain/cart, domain/calendar |
| tier/* | Architecture layer | tier/foundation, tier/service, tier/api |
| operation/* | What it does | operation/read, operation/write, operation/validate |
| effect/* | Side effects | effect/write, effect/send, effect/delete |
| protocol/* | Communication protocol | protocol/sql, protocol/rest, protocol/oauth |
| integration/* | Boundary type | integration/external, integration/internal |
| scope/* | Granularity | scope/inbox, scope/panel, scope/widget |
You can invent any namespace — these are conventions, not restrictions.
EDN Registry Format
An Atlas EDN file is a Clojure map: {compound-identity-set → value-map}.
{#{:atlas/execution-function :domain/auth :operation/validate :tier/service}
{:atlas/dev-id :fn/validate-token
:atlas/type :atlas/execution-function
:execution-function/context [:auth/token]
:execution-function/response [:auth/valid?]
:execution-function/deps #{:component/oauth}}
#{:atlas/structure-component :domain/auth :protocol/oauth :tier/foundation}
{:atlas/dev-id :component/oauth
:atlas/type :atlas/structure-component
:structure-component/deps #{}}
#{:atlas/interface-endpoint :domain/auth :tier/api}
{:atlas/dev-id :endpoint/login
:atlas/type :atlas/interface-endpoint
:interface-endpoint/context [:auth/email :auth/password]
:interface-endpoint/response [:auth/session-token]
:interface-endpoint/deps #{:fn/validate-token}}}How It Works
Atlas JS is not a reimplementation. It compiles the same .cljc source files that run on the JVM to JavaScript via ClojureScript + shadow-cljs:
core/src/atlas/
├── registry.cljc ─┐
├── query.cljc │ Identical source
├── datalog.cljc ├─ compiled to both
├── invariant.cljc │ JVM (Clojure) and
├── ontology.cljc ─┘ JS (ClojureScript)
js/src/atlas_js/
├── core.cljs ← Full: thin interop layer (keyword ↔ string)
└── core_slim.cljs ← Slim: same, without datascriptProject Structure
js/
├── shadow-cljs.edn # Build configuration (4 targets)
├── package.json # npm package
├── src/
│ └── atlas_js/
│ ├── core.cljs # Full JS API (registry + query + datalog + invariants)
│ └── core_slim.cljs # Slim JS API (registry + query + ontology, no datascript)
├── dist/ # Full production build
│ └── atlas.js # 546 KB / 125 KB gzip
├── dist-slim/ # Slim production build
│ └── atlas.js # 291 KB / 72 KB gzip
├── dist-dev/ # Full dev build (source maps)
└── dist-slim-dev/ # Slim dev build (source maps)