Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

94 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

devtooie

A dependency-aware terminal UI (TUI) for running a monorepo's packages during local development.

dev + TUIdevtooie.

You describe your packages once, in a small typed config file. devtooie resolves build-time, dev-time, and runtime dependencies between them, builds whatever needs building (in the right order), and then runs the packages you picked.

devtooie's terminal UI driving the example monorepo

Features

  • Dependency-aware builds. Declare build/dev/runtime deps once; devtooie builds what needs building, in the right order, before it runs anything.
  • Language-agnostic packages. A package is driven through a handful of named scripts, so it can be written in anything: a Node package (via its package.json) or a Go, Rust, … package (via a Makefile with the equivalent targets). See Package supporting scripts.
  • Streamed, filterable logs. Every package's output is streamed live into one combined view; filter it down to a single package or a search term on the fly (the f hotkey; matching is case- and accent-insensitive).
  • Structured logs, by default. devtooie auto-formats every package's JSON logs (Go slog, pino, winston, …) as a colored [LEVEL] message for local dev — no NODE_ENV branching in your app, and nothing to configure. See Logging.
  • Two run modes. An interactive terminal UI to pick and watch packages, or a --plain log-streaming mode for coding agents.
  • One-off commands. devtooie cmd runs a single command (or a package script/target) in a package's directory with that package's resolved environment — for migrations, seeds, scrapers, or an agent driving your project. See Running one-off commands.
  • Per-package hierarchical .env loading. Each package's .env files (workspace- and package-scoped) are resolved and injected into its process automatically — and live-reloaded, restarting the affected package when a file changes.
  • Readiness ordering. healthcheck + waitFor hold a package until the services it needs are actually up.
  • Lifecycle-aware. Each package declares whether its dev process watches or just builds, so you (or an agent) know exactly what to do after a code edit.
  • Control API + agent skill. A localhost HTTP API drives a running session headlessly and lets a second invocation hand off cleanly; an installable skill teaches a coding agent to use it.

Example

A complete, runnable example monorepo lives in example/: four packages — a shared TypeScript library (isomorphic), a Node API (backend), a Go worker driven through a Makefile (worker), and a web frontend — wired up with dependency-aware builds, .env loading, healthchecks, and waitFor readiness ordering.

Requirements

  • Node 20+. A .ts config additionally needs Node ≥23.6 (native type-stripping); on older Node, use a compiled devtooie.config.js/.mjs.
  • Unix only (macOS/Linux). Windows is not supported.
  • pnpm. Node packages are run with pnpm run <script>, and packages that depend on each other are resolved through pnpm workspace links (workspace:*). (Makefile packages are run with make instead.)
  • A package.json (or Makefile) per package with the scripts devtooie drives (dev, build, ...) — see Package supporting scripts below.

Install

pnpm add -D devtooie

Getting started: devtooie init

pnpm devtooie init

This is an interactive, idempotent setup flow. It will:

  1. Ask whether to install the agent skill (recommended: yes).
  2. Scaffold devtooie.config.ts at your repo root (an existing config file is left untouched).
  3. Reconcile a root tsconfig.json so the config type-checks with Node globals in scope (idempotent — your other settings are left untouched).
  4. If you opted in to the skill, install it.

Pass -y/--yes to accept the defaults non-interactively.

After that, fill in the scaffolded config's packages array with your real packages (see below) and run pnpm devtooie.

devtooie.config.ts

The one file you author and commit — the single source of truth the CLI reads on every run.

import { defineConfig } from 'devtooie';

export default defineConfig({
  packages: [
    {
      name: 'core-api',
      port: 3001, // is provided as PORT environment variable to the process
      // `$port` is substituted with this package's `port`.
      healthcheck: 'http://localhost:$port/health',
    },
    {
      name: 'worker',
      // a dev process that doesn't watch files: it builds once, then runs. devtooie
      // doesn't watch your source, so after you edit its code you (or an agent, via the
      // control API) restart it — the command's flags say which. See docs/package-lifecycle.md.
      command: ['start', { watches: false, builds: true }],
    },
    {
      name: 'web',
      port: 3000,
      waitFor: ['core-api'], // hold until core-api's healthcheck passes
      deps: { runtime: ['core-api'] }, // selecting web also runs core-api
    },
  ],
});

See Configuration options for every defineConfig and package field.

Running the Terminal UI

pnpm devtooie

Package supporting scripts

devtooie drives each package through named scripts — a Node package declares them in its package.json scripts; a package in any other language (Go, Rust, …) declares the equivalent make targets in a Makefile. devtooie invokes them as pnpm run <name> or make <name>.

  • dev — the long-running process devtooie starts and streams. An application usually needs only this; devtooie builds its dependencies for it.
  • build — a shared library that other packages build against adds this too, so devtooie can build it in the build phase before its dependents start.

A shared library (Node) — dev + build:

// packages/shared/package.json
{
  "name": "shared",
  "scripts": {
    "dev": "tsc --watch", // re-emits dist on change
    "build": "tsc",
  },
}

An application needs only a dev process — a Node backend:

// packages/backend/package.json
{
  "name": "backend",
  "scripts": {
    "dev": "node --watch src/index.ts",
  },
}

…or a Go program, via a Makefile:

# packages/worker/Makefile
.PHONY: dev
dev:
	@go run .

An app can add build + clean too, for the occasional case where you need to rebuild it from scratch to clear stale build output — those enable the rebuild command (the b hotkey / POST /command/rebuild); see Package lifecycle.

Running one-off commands (devtooie cmd)

Sometimes you don't want the whole session — you just need to run one command with a package's exact environment: a migration, a seed script, a scraper, a REPL. devtooie cmd does that. It runs a command in a package's directory with that package's resolved env vars injected — the same environment the TUI would give it:

cd packages/api
devtooie cmd -- pnpm run migrate     # a literal command, in api's dir with api's env
devtooie cmd -c seed -- --rows=100   # run api's `seed` script/target, forwarding args
cd ../..
devtooie cmd -p api -- pnpm start    # or target a package by name, from anywhere

The package is inferred from your current directory (or named explicitly with -p). Output streams to your terminal and is also written to a logfile. It's especially handy for a coding agent driving your project. Full reference: devtooie cmd.

Configuration options

The full defineConfig and per-package field reference — including dependencies, TypeScript project references, and typed package names — lives in docs/configuration.md.

Logging

devtooie auto-formats structured (JSON) logs — from Go slog, pino, winston, … — into a colored [LEVEL] message for local dev, with no NODE_ENV branching and nothing to configure. You can add on-screen timestamps, and override or customize the formatter per package. See docs/logging.md.

Every session is also teed to a timestamped logfile. Read the current one from another terminal with devtooie logs (or devtooie logs -f to follow it live) — see devtooie logs.

Package lifecycle when you edit code

A package's command flags declare whether its dev process watches or just builds, which tells you (or an agent) whether to restart or rebuild it after a code edit. See docs/package-lifecycle.md.

Environment (.env) loading

devtooie loads .env files for every package it runs and injects them into that package's child process — merged over the current process.env without mutating it. Parsing is handled by dotenvx under the hood. Files are resolved at two scopes: the workspace root and the package's own directory. Only files that exist are loaded.

your-monorepo/
├── .env                     # workspace scope — base for every package
├── .env.local               # workspace scope, higher precedence
└── packages/
    ├── core-api/
    │   ├── .env              # package scope — overrides workspace scope
    │   └── .env.local        # highest precedence for core-api
    └── web/
        └── .env

Default files, ascending precedence within a scope:

  1. .env
  2. .env.development
  3. .env.local

Package scope overrides workspace scope, and within a scope a later file overrides an earlier one. ${VAR} references expand against already-loaded files and the current environment; file values win over the ambient environment (so NODE_OPTIONS=$NODE_OPTIONS --flag extends the inherited value).

A package's port is also injected as PORT (an explicit .env PORT still overrides it).

Customize the list via env.files (each name is still resolved at both scopes):

defineConfig({
  env: { files: ['.env', '.env.local'] },
  packages: [/* … */],
});

While a session runs, devtooie watches these files (and where new ones would appear) and restarts the affected package(s) on change — editing a workspace-level file restarts every running package that uses it.

The same resolution is available as a standalone command: from inside a package's directory, devtooie cmd -- <command> runs a one-off command in that package's dir with its resolved env (or invoke one of its scripts/targets with -c) — see devtooie cmd.

Advanced CLI usage

Every flag and subcommand — plus devtooie cmd for running a command in a package's environment on demand — is documented in docs/cli.md.

Agent skill

If you opt in during devtooie init, devtooie installs an agent-facing skill file at .claude/skills/devtooie/SKILL.md (and, best-effort, under .agents/ / .cursor/ if those directories already exist). It teaches a coding agent how to run devtooie headlessly (--plain -p <package>), drive a running session through the control API, read the logfile for debugging, and onboard a new package. The installed file is managed — treat it as generated, not something to hand-edit. devtooie init and every devtooie run refresh it to the installed version.

The skill points the agent at a single consolidated guide, packages/devtooie/docs/agents.md — the same material as this README plus how to drive devtooie headlessly, in one self-contained file. It's the one doc that ships inside the package (so the skill can load it from node_modules); the topic docs above live at the repo root.

Control API

While a session runs, devtooie exposes a localhost-only HTTP API for driving it (restart/rebuild a package, query status, hand off between invocations). See docs/control-api.md.

License

MIT

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages