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

@cratylus/forge

v0.22.0

Published

The deterministic projection from canonical meaning onto one harness’s surfaces — resolve, project and install the canon. Owns the mapping and nothing else.

Readme

@cratylus/forge

The build core for cratylus: it resolves a plugin set into one merged set of agents, skills, values and hooks, renders that set into the files a harness reads, and installs them.

This README is for whoever works on the library, or on an adapter for a harness. What the product owner does with the cratylus command — install and its flags, starting a session as an agent, the badge, uninstall — is the cratylus README's, which documents each command to match its --help.

Agents, skills, values and hooks are typed TypeScript declarations inside plugin packages. forge resolves a plugin set into one merged canon, projects it into harness artifacts, and install places them on the local machine.

The direction matters. The canon is the source; OMP's home (~/.omp/) is a projection of it. Nothing in this pipeline reads a harness's existing configuration and treats it as truth.

The pipeline

resolve → project → install

| Stage | What it does | | --------- | --------------------------------------------------------------------------------------------- | | resolve | resolves the plugin set into one merged set of agents, skills, values and hooks | | project | renders the resolved set into a render tree, in memory (projectPluginSet) | | install | places the render tree as the owned root and refers OMP's home into it, user or project scope |

Projection goes from composed agents and skills to OMP artifacts directly, through forge's adapter port. The plugin set install projects is the canon the cratylus command is built with.

Rendering a tree

projectPluginSet materializes the resolved set into a render tree: agents/, skills/, and hooks/. OMP hook modules are emitted under enforcing/<scope>/; skills that need a runtime companion get their shim emitted alongside them. A shim forwards its arguments to cratylus <capability> with the caller's environment, and it needs no session from any harness.

A render is the whole plugin set

projectPluginSet renders every agent, skill and hook the plugin set declares; an install places them all. The one choice a render takes is which rules to place (ProjectOpts.rules), and the tree reports the offered rulesets (ProjectedTree.rulesets) for an install to offer.

An agent is given its skills' closure

An agent's skills are the names it declares; what projection gives it is their closure over composition: the declared names first, then every skill they transitively compose, breadth-first in each skill's declaration order, each name once. Each composed name is resolved against the set's resolved skills, so a later plugin's same-name skill changes the closure, a name no plugin ships is kept and not expanded, and a composition cycle terminates. The closure is computed once, before any agent is rendered; every adapter renders the list it is handed.

OMP receives each agent's skill closure in autoloadSkills, which it preloads for a dispatched subagent; for a main session started by omp --agent <name> the cratylus extension carries the same skills' full instructions in every turn's system prompt.

An agent's text, and the settings its reach and model bind to

An agent's text is rendered from its values: # <mark> <name> (the name alone without a mark), its description, then one section per factor group in catalog order, each value as its term and precising definition, marked (fixed) where its level is fixed. A factor the agent holds no value of states no departure and renders no section, nor does a group all of whose factors are empty. Reach (perception-scope, action-scope) and model are never text. On OMP the definition's front matter carries model: "@<name>", the model role named for the agent, and spawns: "*": every agent keeps omp's default tools and may dispatch any agent. key: null reserves the key of an ipseic agent. The tree reports each agent's tier and effort (ProjectedTree.agentModels), from which each declaration's model falls back to after its own role.

How install places a tree

A render tree is placed WHOLE as the owned root, ~/.cratylus/<harness>/ at user scope and <project>/.cratylus/<harness>/ at project scope (deploy/owned-root.ts): agents under agents/, skills under skills/, extension modules under extensions/, hook workers under hooks/, a package.json naming the modules (omp.extensions) and recording the version that projected it, runtime.json where the canon configures a capability, and installation.json, the record of every reference placed outside the root and every host-file edit. The harness's own surfaces only refer into it (linkOwnedRoot: for omp, a link in ~/.omp/plugins/node_modules and a dependency entry in ~/.omp/plugins/package.json), so uninstall (unlinkOwnedRoot, then the root) removes exactly those, each found from where it points into the root rather than from the record, so none is left dangling when the root or its record was edited or removed. An installation from before the owned root is taken back by its deploy manifest (removeEarlierInstallation), what it placed before digests were recorded included.

Model routing is host configuration, not a placed artifact: a declaration names its own role first, then its tier and effort, and is never rendered with a model. Which model a tier or a persona's role runs on is the product owner's choice (design/decisions/install-keeps-each-tiers-model-as-the-hosts-setting.md): install asks for each the host does not bind and writes the answer into the host's modelRoles as the host's own entry, recorded in no installation record, so upgrade and uninstall keep it; an earlier installation's seeded entries stay the same way.

The destinations are the adapter's, not the render tree's

A render tree is forge's staging layout — agents/<name><ext>, skills/<name>/, hooks/<id>/ and scoped artifacts under enforcing/<scope>/. It is deliberately not the harness's layout. Install asks the adapter where each artifact belongs:

| Artifact | Port op | OMP | | ------------------------------- | ------------------------ | ------------------------------ | | agent definition | agentRel(name) | agent/agents/<name>.md | | skill directory | skillRel(name, agents) | ../.agents/skills/<name> | | hook module | hooksFile | generated extension module | | scoped mechanism module | scopedRel(file, scope) | agent/extensions/<file> | | capability and --agent module | scopedRel(file, scope) | agent/extensions/cratylus.ts |

OMP has one scope, the session's: omp loads agent/extensions/ in every session and cannot load a module for one agent alone, so scopes answers no for every event, and an enforcing value bound to agents degrades to a steer, reported as a hook omp cannot scope per agent. Nothing is placed under agent/personas/; a reinstall prunes what an earlier install recorded there, and uninstall removes it.

The definition is the single source of truth. OMP reads agent/agents/<name>.md when it dispatches an agent as a subagent, and omp --agent <name> resolves the same declaration through omp's own discovery to start it as a main session, through the cratylus extension, holding the whole declaration as dispatch resolves it for a child: its text, model, effort, autoload-skills, read-summarize, advisor and prewalk, and no default personality. Where omp's own dispatch drops what the declaration says, launch holds what it says — a known omp limitation: read-summarize: true turns summarised reads on (omp's dispatch applies only false). One definition, no launcher, nothing to drift. Every turn carries the handover form of each agent that takes a typed one. The extension records nothing of a dispatch or its return.

The harness adapter port

A harness adapter implements HarnessAdapter (@cratylus/forge/harness-adapter) and is selected by name through adapterByName. OMP is the current implementation; projection and install depend on the port, not on OMP's concrete rendering functions.

| member | what the harness says | | --------------------------------------------------- | ------------------------------------------------------------------------------------------- | | name, substrate, home, agentExt | its canonical name, substrate, dot-directory and agent-definition extension | | agentRel, skillRel, hooksFile | where an agent, skill and hook module land, relative to the harness home | | agentDef, skillDef, hooks | how an agent, skill and hook registration are rendered | | preloadsSkills, mainSessionSkillHook | whether an agent definition preloads skills and how a main session gets them | | nativeEvents, realizes, scopes, hookCommand | the event map, supported events, narrowing and worker invocation | | enforcingSurface, scopeActivatedSurface | the emitted hook surface when OMP loads extension code rather than a settings fragment | | scopedRel | where a scoped artifact lands for an agent or the session | | launchSurface | what is composed from the agents beyond their definitions (OMP's dispatch isolation module) | | capabilitySurface | the capability tools, and on OMP the --agent flag that starts a session as an agent | | statusSegment | how a session's agent appears in OMP's segmented status line |

An event absent from nativeEvents is unrealizable, and projection reports it rather than fabricating a binding. scopes is a stronger demand than realizes: firing is not scoping, and an adapter must never answer yes for an event it cannot realize. hookCommand is written against $CRATYLUS_INSTALLATION, not a resolved path, because it is read at runtime wherever its installation lands; on OMP the session module sets that variable to its own root for every hook it runs, so a project installation runs its own workers.

scopedRel places a scoped module in its scope's extensions/ directory, and on OMP every scope is the session's. launchSurface receives the composed agents once.

Where the boundaries are

Three concerns look adjacent to this pipeline and are deliberately outside it.

Delivery is npm's. Getting cratylus and the packages it composes onto a machine is an ordinary package install. It is a precondition of the pipeline, not a stage of it.

Placement is local. install writes to the machine it runs on. It has no transport, no host list, and no remote mode.

Running it across many hosts is yours. Iterating a fleet is an outer loop around the whole pipeline, and it is a site-specific concern rather than a feature of this tool. The loop ssh's to each host, installs the package, and runs cratylus install there. forge is the body of that loop, not the loop.

Library surface

The command is a thin shell over exported functions. The subpaths that back the pipeline:

import { projectPluginSet } from '@cratylus/forge/project';
import { adapterByName } from '@cratylus/forge/adapters/registry';
import { projectorCommands } from '@cratylus/forge/cli';

adapterByName is the single selection point for a harness adapter. OMP is its one implementation; consumers depend on the adapter port and selector rather than on concrete rendering functions. The declaration types and defineAgentPlugin are @cratylus/schema's, so the projector holds no declaration shape of its own.

The other subpaths are ./harness-adapter (the port and its staging constants), ./catalog (the value catalogs of a plugin set), ./module-scan and ./adapters/omp (the OMP adapter).

License

MIT © Lance Caraccioli — see LICENSE.