The nervous system for AI agents that watch, notice, and act without being asked.
RE: The art. Yes, it's AI-generated. Looking for an actual artist to pay for a real logo. If you know someone good, open an issue.
Most AI agents are request-response: you ask, they answer. But staff members don't wait to be asked — they notice things and bring them to you.
Cadence closes that gap. It enables ambient agency: agents that observe file changes, webhook events, scheduled triggers, and act autonomously based on what they see.
npm install @peleke.s/cadence
# or
pnpm add @peleke.s/cadenceimport { createSignalBus, createFileWatcherSource, type DefineSignals } from "@peleke.s/cadence";
// Define your signal types
type MySignals = DefineSignals<{
"file.changed": { path: string; event: "add" | "change" | "unlink" };
"task.found": { file: string; task: string; done: boolean };
}>;
// Create a bus
const bus = createSignalBus<MySignals>();
// Subscribe to signals
bus.on("file.changed", async (signal) => {
console.log(`File ${signal.payload.event}: ${signal.payload.path}`);
});
// Create a source
const watcher = createFileWatcherSource<MySignals>({
paths: ["./notes"],
toSignal: (event) => ({
type: "file.changed",
ts: Date.now(),
id: crypto.randomUUID(),
payload: { path: event.path, event: event.type },
}),
});
// Start watching
await watcher.start((signal) => bus.emit(signal));Cadence is built with pluggable interfaces:
| Interface | Purpose | Default |
|---|---|---|
| Transport | How signals move | MemoryTransport (in-process) |
| Store | Durability layer | NoopStore (no persistence) |
| Executor | Handler concurrency | SequentialExecutor |
Build for the sophisticated case, implement simple defaults.
import {
createSignalBus,
createMemoryTransport,
createNoopStore,
createSequentialExecutor
} from "@peleke.s/cadence";
// Explicit configuration (these are the defaults)
const bus = createSignalBus<MySignals>({
transport: createMemoryTransport(),
store: createNoopStore(),
executor: createSequentialExecutor(),
});- Type-safe signals —
DefineSignals<M>creates discriminated unions - Middleware — Transform, filter, or log signals before handlers
- Signal replay — Replay unacked signals from store on restart
- Pluggable everything — Swap transport, store, executor as needed
- File watcher source — Built-in chokidar integration
- Ambient Obsidian agent — Watch your vault, extract tasks, act on them
- PR delegate — Watch journals, cluster insights, draft social posts
- Proactive pair programmer — Watch code changes, surface forgotten TODOs
- Multi-agent coordination — Agents communicate via signal emission
Create a signal bus with optional pluggable components.
const bus = createSignalBus<MySignals>();
bus.on("file.changed", handler); // Subscribe to specific type
bus.onAny(handler); // Subscribe to all signals
bus.use(middleware); // Add middleware
bus.emit(signal); // Emit a signal
bus.clear(); // Remove all handlers
bus.stats(); // Get bus statistics
bus.replay(); // Replay unacked signals from storeCreate a file watcher that emits signals on file changes.
const watcher = createFileWatcherSource<MySignals>({
paths: ["./notes", "./tasks"],
toSignal: (event) => ({ /* map to your signal type */ }),
chokidarOptions: { /* optional chokidar config */ },
});
await watcher.start(emitFn);
await watcher.stop();MIT License. See LICENSE.