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

@elementumai/edk

v0.9.6

Published

Elementum Development Kit — statically typed SDK for building Elementum apps, automations, and agents

Readme

@elementumai/edk

Statically typed TypeScript SDK for authoring Elementum apps, elements, automations, agents, skills, search tables, and related configuration as code. @elementumai/edk is SDK-only; the standalone elementum CLI is distributed separately as part of the signed toolchain.

This repository is the canonical source for the public SDK, the standalone elementum CLI, the OpenTofu provider under provider/, and the temporary private bridge under cmd/elementum/. The installed toolchain manages the bridge and OpenTofu; neither is a separate public executable or checkout.

Installation

Install the authenticated macOS or Linux x64 toolchain:

curl -fsSL https://install.elementum.tools | sh
elementum init

The installer places elementum in ~/.elementum/bin and adds that directory to PATH via your shell profile (~/.zprofile for zsh, otherwise the applicable profile file). The current shell won't see it until the profile reloads.

Install the SDK in the package workspace that contains your Elementum org folders:

npm install @elementumai/edk

Use Node 24 or newer. The npm package is the authoring SDK; the only public executable is elementum.

Platform support

The authenticated elementum toolchain targets macOS Apple Silicon (darwin-arm64), macOS Intel (darwin-x64), and Linux x64 (linux-x64, glibc). Linux distribution work is tracked in #186. The authoring SDK (@elementumai/edk) remains pure TypeScript and runs anywhere Node 24+ runs.

Authentication and profiles

The SDK is credential-free and never calls the platform. Authentication and all platform I/O are owned by the managed private bridge:

elementum auth login --profile <profile>
elementum --profile=<profile> auth status

A profile selects the organization, instance, optional organization environment, credentials, and custom endpoints. Pass it explicitly before any command when reproducibility matters:

elementum --profile=<profile> pull org --data-only
elementum --profile=<profile> plan

For plan and apply, --profile is optional. The CLI resolves the marked org root from the explicit target or current directory, including targets nested under apps/, elements/, or an individual authored file. It reads <instance>/<organization> from that org root's path and selects the one saved profile with the same identity. It does not infer tenant identity from shell variables.

An explicit --profile overrides filesystem selection. The existing safety check still rejects that profile if its instance or organization differs from the workspace path. If no saved profile matches, or multiple profiles have the same filesystem identity, the command fails before planning with the workspace identity and tells you to pass --profile explicitly. Commands that bootstrap a workspace should use an explicit profile because no org root exists yet.

Workspace setup

Start from the parent directory that will contain one or more <instance>/<organization> workspaces:

mkdir elementum-workspace
cd elementum-workspace
npm init -y
npm install @elementumai/edk
elementum auth login --profile <profile>
elementum --profile=<profile> pull org --data-only
cd <instance>/<organization>
elementum --profile=<profile> init

pull org --data-only bootstraps and refreshes org reference identities. Plain pull org additionally writes editable organization.ts, adopts supported org-owned resources, and keeps the generated org.ts catalog separate. It creates the package/workspace scaffolding, org.ts, the @catalog path alias, and the Terraform input/output skeleton:

<workspace>/
  package.json
  <instance>/
    <organization>/
      org.ts
      organization.ts       # editable org resources after plain `pull org`
      tsconfig.json
      backend.tf               # optional locking backend; user-owned and committed
      terraform.tfstate        # committed local state when backend.tf is absent
      apps/
      elements/
      generated/
        catalog.ts
      .tf/                     # generated and ignored
        in/                    # bridge export input
        out/                   # SDK build output

elementum init is an idempotent installation/workspace convergence command. It verifies the managed compatibility train, auth, SDK namespace/version, workspace layout, and provider identity. It never logs in or silently migrates Terraform state.

Do not hand-edit org.ts, generated/, or .tf/. Refresh those through their owning commands.

Recommended flow

Pull first when editing an object that already exists:

cd <workspace>/<instance>/<organization>
elementum --profile=<profile> pull org --data-only
elementum --profile=<profile> pull app <namespace>
# or: elementum --profile=<profile> pull element <namespace>

# edit apps/<ref>/... or elements/<ref>/...
npx tsc --noEmit
elementum build
elementum --profile=<profile> plan
elementum --profile=<profile> apply

pull app and pull element reconstruct editable TypeScript, regenerate the catalog, then automatically adopt the exported resources into the configured Terraform state. Adoption is gated to exactly the expected imports, zero create/update/destroy operations, and a clean follow-up plan. Use --no-adopt only when you deliberately want source without state adoption.

Pull commands reserve stdout for one JSON summary. Diagnostics and stream kinds that do not yet have an extractor are reported rather than silently discarded.

CLI commands

The TypeScript-owned command surface is:

elementum init [--check] [--json]
elementum update [--check | --dry-run] [--channel stable|preview] [--version <semver>]
elementum migrate backend [orgRoot] [--check | --dry-run | --auto-approve] [--reconfigure]
elementum migrate provider-source [orgRoot] [--check | --dry-run | --auto-approve]

elementum pull org [--root <orgRoot>] [--no-adopt]
elementum pull org --data-only [--root <orgRoot>]
elementum pull app <namespace> [--root <orgRoot>] [--no-adopt]
elementum pull element <namespace> [--root <orgRoot>] [--no-adopt]
elementum clone app <namespace> --as <newName> [--namespace <newns>] [--root <orgRoot>]
elementum build [orgRoot]
elementum plan [orgRoot-or-nested-target] [bridge args...]
elementum apply [orgRoot-or-nested-target] [bridge args...]

elementum list apps|elements|users|groups|categories|cloud-links
elementum list ai-provider-connectors|automations|tables
elementum new app --name "Support Tickets" --namespace support --category "Operations"
elementum new element --name "Locations" --namespace locations --category "Operations"
elementum new agent --app <appRef> --name "Triage Bot"
elementum new skill --app <appRef> --name "Lookup Ticket"
elementum new automation --app <appRef> --name "Escalate Ticket"
elementum generate [path] [--root <orgRoot>]
elementum canvas <orgRoot-or-file> [--port <port>] [--no-open]
elementum playbooks list|install|status|path|print

auth and other bridge-owned commands route through the managed bridge. Run elementum --help for the combined local and bridge command surface.

build loads app, element, and supported child authoring files and replaces its marker-owned files under .tf/out/; it never calls the platform. plan and apply run from .tf/out/, initialize OpenTofu there when necessary, and forward extra arguments:

elementum plan <instance>/<organization>/apps/myApp/myApp.ts
elementum --profile=<profile> apply <instance>/<organization> -auto-approve

The optional path may be the org root or anything nested beneath it. Run from any directory inside the marked org workspace to omit it. The CLI always runs the bridge/OpenTofu pass-through from that root's .tf/out/; it does not scan or deploy an individual target file.

new app and new element create offline org-root scaffolds — the initial authoring file for a brand-new app or element with no existing platform counterpart — and immediately register the new entity in the org's generated catalog. new agent, new skill, and new automation create offline app-owned scaffolds without overwriting an existing ref (automations are app-owned only, for now). Here, skill means an Elementum agentic skill attached to an agent.

generate resyncs generated/catalog.ts files with whatever authoring source is currently on disk — the fix for hand-editing an existing file (e.g. adding an automation's onDemand trigger parameter or an .outputs() key) rather than running one of the new/pull/clone commands that regenerate the catalog as a side effect of writing a brand-new file. Pass a path to scope it to one app/element; omit it to resync the whole workspace. It always refreshes the org-level barrel too.

Coding-agent guidance is packaged separately as playbooks (Agent Skills-standard SKILL.md directories):

elementum playbooks list
elementum playbooks install --yes

The installed slash commands are /elementum, /elementum-uat, /elementum-debug, /elementum-deployments, and /elementum-design. elementum skills ... remains the platform command family for agentic-skill operations.

Canvas

Canvas is an offline, live-reloading view of authored source:

elementum canvas <instance>/<organization>
elementum canvas apps/myApp/automations/someAutomation.ts

A directory target opens the workspace explorer at http://localhost:3456, covering pulled org identities, apps, fields, status/stages, agents and their tools, and supported automations. A file target renders the first export with toUI() (or .build().toUI()). Use --port <port> to choose another port or --no-open to suppress browser launch.

Package imports

Import public package subpaths, not repository-relative modules:

import { calc, app } from "@elementumai/edk/app";
import { element } from "@elementumai/edk/elements";
import {
  actions,
  automation,
  onDemand,
} from "@elementumai/edk/automations";
import {
  agentCreateRecord,
  agentRunAutomation,
  agentSearchRecords,
  agent,
} from "@elementumai/edk/agents";
import { skill } from "@elementumai/edk/agents/skills";
import { linkedSearchTable, searchTable, searchTableDuration } from "@elementumai/edk/searchTables";
import { approvalProcess } from "@elementumai/edk/approvalProcesses";
import { table } from "@elementumai/edk/tables";
import { eq } from "@elementumai/edk/core/filters";
import catalog from "@catalog";

The package exports and typesVersions map are kept in lockstep. Generated source uses the same public subpaths.

Authoring model

EDK uses names and typed tokens in source, with the configured OpenTofu state backend providing platform identity:

  1. pull org --data-only writes org reference bags to org.ts, including cloud links, phone providers, categories, connectors, and groups. Plain pull org also writes editable categories, groups, CloudLinks, email aliases, and Twilio providers to organization.ts.
  2. pull app or pull element writes editable source and adopts existing resources into the required locking remote backend.
  3. generated/catalog.ts is a pure barrel derived from the authored file tree. Import app/entity tokens from @catalog; import org tokens from org.ts.
  4. build converts TypeScript to the one supported HCL dialect in .tf/out/.
  5. OpenTofu resolves references and computes create/update/replace/destroy behavior during plan and apply.

There are no UUIDs or minted handles in authored source. The TypeScript bag key is the Terraform label in camelCase through a lossless label conversion. For example, a field's key in fields: {} is its identity; its display name can change.

Organization credentials use secret("variableName"); the build emits a sensitive Terraform variable and reads its value from TF_VAR_variableName. Pull never serializes write-only credentials. It leaves redactedSecret(...) or unavailableValue(...) markers and reports those addresses as skipped until the missing input is supplied, while still adopting fully recoverable org resources.

Configured builders such as agent and automation return { ref(refName), def(refName) }. Workspace discovery supplies the ref name from the file path. There is no .deploy() method.

Automation example

The Terraform path round-trips typed triggers and actions. Public authoring uses direct fluent action methods; provider task resource names remain an internal wire concern.

import { automation, onDemand } from "@elementumai/edk/automations";
import { template } from "@elementumai/edk/core";
import catalog from "@catalog";

export default automation({
  name: "Greet New Student",
  app: catalog.students,
  revision: "1.0.0",
  actions: actions()
    .trigger(onDemand({ STUDENT_NAME: "text" }))
    .setVariable("GREETING", {
      value: (ctx) => template("Welcome, ", ctx.trigger.STUDENT_NAME),
    })
    .executeScript("FORMAT_GREETING", {
      inputs: (ctx) => ({ greeting: ctx.variables.GREETING }),
      code: (input) => ({
        message: `${input.parameters.greeting}!`,
      }),
    })
    .outputs((ctx) => ({
      message: ctx.actions.FORMAT_GREETING.result.message,
    })),
});

The file path supplies the automation ref; app is the strongly typed owning app ref. revision is required SemVer and is the explicit publish gate. Editing actions or triggers updates the draft; bump the revision only when that draft should be published.

Agent example

Agents live under apps/<appRef>/agents/<agentRef>.ts. Their connector comes from the org catalog, while app and field targets come from @catalog:

import { agentSearchRecords, agent } from "@elementumai/edk/agents";
import catalog from "@catalog";
import { org } from "../../../org.js";

export default agent({
  name: "Support Agent",
  app: catalog.support,
  connector: org.connectors.claudeSonnet,
  description: "Finds support records.",
  instructions: "Search records and summarize the next action.",
  tools: [
    agentSearchRecords({
      name: "find_records",
      description: "Searches support records.",
      app: catalog.support,
      queryDescription: "Describe the record to find.",
      fields: [
        {
          field: catalog.support.fields.status,
          description: "Current status",
        },
      ],
    }),
  ],
});

The Terraform path currently round-trips create-record, record-search, and run-automation agent tools. Unsupported tools and runtime-only knobs are reported as build diagnostics instead of being emitted as partial resources. Authored tool names use 1–64 letters, digits, or underscores, with no doubled underscores.

Plan and apply

Always build before planning:

cd <workspace>/<instance>/<organization>
elementum build
elementum plan
elementum apply

plan and apply are pass-throughs to the managed bridge with inherited stdio. With no explicit profile, the CLI selects the unique saved profile matching the org root's <instance>/<organization> path. Review destroy and replacement actions just as you would in any Terraform plan.

Identity and state recovery

Terraform state is the durable binding between authored labels and live platform objects. For backwards compatibility, a workspace without <orgRoot>/backend.tf continues to use the committed root terraform.tfstate through a generated local backend. This preserves existing single-author workspaces, but it provides no state locking; avoid concurrent plan/apply operations in that mode.

Shared workspaces and CI should commit one user-owned, non-secret <orgRoot>/backend.tf containing a complete terraform { backend "TYPE" { ... } } declaration with verified locking. elementum build projects either that declaration or the compatibility local backend into .tf/out/backend.tf. Never commit .terraform/, .tf/, backend credential files, or saved plan files. After migrating to remote state, remove and stop committing the root terraform.tfstate.

For example, an S3 backend with native locking can be declared as:

terraform {
  backend "s3" {
    bucket         = "elementum-team-state"
    key            = "prod/acme/terraform.tfstate"
    region         = "us-east-1"
    dynamodb_table = "elementum-state-locks"
    encrypt        = true
  }
}

The backend body remains native OpenTofu HCL, but EDK validates the locking contract. Native-locking backends azurerm, cos, gcs, kubernetes, pg, and remote are accepted. consul must omit lock (the default is true) or set lock = true. s3 must set use_lockfile = true or dynamodb_table; http must set both lock_address and unlock_address; oss must set both tablestore_endpoint and tablestore_table. Optional-backend lock settings must be literal so EDK can verify them before state access. An explicitly authored local backend, unlocked/unknown backends, and configurations EDK cannot verify fail closed; the generated local compatibility backend is the only local exception. The storage and locking infrastructure and access policies must already exist; EDK does not provision them.

Backend authentication must use that backend's standard environment or workload-identity chain: for example AWS/GCP/Azure OIDC, an IAM role, or environment variables supplied by CI. Do not put access keys, passwords, tokens, secret-manager data sources, or credential paths in backend.tf. Backend initialization happens before providers and data sources, so it cannot read a Terraform-managed secret. EDK does not accept -backend-config secrets and never writes backend credentials into generated HCL.

OpenTofu owns locking. EDK does not implement a weaker parallel lock or disable native locking: plan, apply, adoption imports, rename state mv, and state-repair operations use the declared backend. Standard options such as -lock-timeout=5m pass through:

elementum --profile=<profile> plan <orgRoot> -lock-timeout=5m
elementum --profile=<profile> apply <orgRoot> -auto-approve -lock-timeout=5m

Backend initialization is lazy and noninteractive. A per-working-directory fingerprint prevents ordinary plan/apply/state commands from silently re-binding a changed backend; use the guarded migration command instead.

Migrate committed local state to a remote backend

Create the backend infrastructure first, then add and review backend.tf. The migration uses native tofu init -migrate-state, takes an ignored recovery snapshot, refuses to overwrite unrelated destination state, verifies lineage/resources, removes the obsolete root copy, and requires a final zero-change plan:

elementum migrate backend <orgRoot> --check
elementum migrate backend <orgRoot> --dry-run
elementum migrate backend <orgRoot> --auto-approve
elementum --profile=<profile> plan <orgRoot>

For a remote-to-remote change, edit backend.tf and run the same migration. Use --reconfigure only to bind an already-populated destination without copying the currently bound state. It is rejected while local committed state still exists.

Recovery snapshots and exact rollback commands are printed on failure and kept under .tf/migration-backups/backend/. The command updates .gitignore but does not rewrite Git history or mutate the index. After a successful local-to-remote migration, commit the root-state deletion with backend.tf and .gitignore; review the diff before pushing:

git add backend.tf .gitignore
git add -u terraform.tfstate
git commit

If state is lost, do not apply the built configuration: OpenTofu would see the live objects as new. Restore/push the recovery snapshot or re-adopt each stream with:

elementum --profile=<profile> pull org --data-only
elementum --profile=<profile> pull app <namespace>
elementum --profile=<profile> pull element <namespace>

After an update reports an old provider identity, inspect and explicitly migrate the configured state:

elementum migrate provider-source <orgRoot> --check
elementum migrate provider-source <orgRoot> --auto-approve
elementum --profile=<profile> plan <orgRoot>

The migration reads the configured local or remote state, creates an ignored recovery snapshot, runs backend-bound OpenTofu state replace-provider, refreshes generated provider configuration, and never applies infrastructure.

CI/CD

Use a serialized protected deployment job and let the backend lock arbitrate all writers. Supply Elementum auth through the bridge's CI profile setup and backend auth through workload identity/environment variables. A current GitHub Actions job (the public signed toolchain is macOS-only today) looks like:

jobs:
  apply:
    runs-on: macos-14
    concurrency:
      group: elementum-prod
      cancel-in-progress: false
    permissions:
      contents: read
      id-token: write
    steps:
      - uses: actions/checkout@v4
      - run: npm ci
      - run: elementum build ./us/acme
      - run: elementum --profile=ci plan ./us/acme -lock-timeout=5m
      - run: elementum --profile=ci apply ./us/acme -auto-approve -lock-timeout=5m

The command sequence and environment contract are identical on a noninteractive Linux runner when your organization supplies the Linux toolchain artifact; the public installer does not yet distribute Linux binaries.

Create and update semantics

Terraform owns lifecycle decisions; EDK has no second deployment state machine:

  • Configured resource absent from state: create.
  • Resource present in config and state with changed attributes: update in place or replace, according to provider schema.
  • Resource present in state but absent from built config: destroy.
  • Existing platform resource mapped into state by pull: adopt.

Pull adoption's zero-write gates prevent an existing resource from being mistaken for a create. Build diagnostics are part of the safety contract: unsupported stream kinds are never silently adopted or emitted. Renames that change an exported Terraform label are guarded during adoption and rebound with state moves when the existing platform identity can be proven.

Development

The repository builds three distinct output trees:

  • dist-sdk/tsc -p tsconfig.sdk.json output, the sole source tree packed into the @elementumai/edk SDK package;
  • dist-cli/ — Node-compatible tsc -p tsconfig.cli.json output used by local development, tests, integration tooling, and the binary build script; it is not part of the SDK package or the final release payload;
  • dist-bin/ — standalone elementum executables produced from dist-cli by the locked local Bun dependency; these are the CLI release inputs distributed separately from npm.

The repository's principal source roots are siblings:

src/                 # TypeScript SDK and public CLI
cmd/elementum/       # temporary private Go bridge module
provider/            # OpenTofu provider module
distribution/        # registry and installer package

Contributor setup, change-specific tests, Go/provider checks, and pull-request verification are documented in CONTRIBUTING.md. The shortest local CLI path is:

npm run local:setup
npm run elementum -- --help
npm run test:cli

See binary validation for release and compatibility-train checks.

Contributor integration harness

The Preston High harness creates, mutates, renames, and deletes live resources. Use only a dedicated test organization and profile. The complete setup, required org identities, golden-workspace flow, command flags, and failure semantics live in the Golden integration test.