npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@semantic-namespace/atlas

v0.1.0-alpha

Published

Atlas semantic registry for JavaScript — query, analyze, and reason about software architecture

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 clean

Quick 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-extractor entities). 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 datascript

Project 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)