Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
322392a
feat(agentic-org): observe.ts run-state keystone + ZetaId/git-sync + …
maximdolphin May 30, 2026
e4e1014
feat(agentic-org): git-as-database-and-event-store via frontmatter + …
maximdolphin May 30, 2026
53c0e34
feat(agentic-org): frontmatter YAML codec, schema<->SQL + git<->cockr…
maximdolphin May 30, 2026
8f36fee
feat(agentic-org): git/cockroach sync adapters + reconcile worker; qu…
maximdolphin May 30, 2026
55eedcd
feat(agentic-org): slice 1 — state reconciliation table (North Star p…
maximdolphin May 30, 2026
fe42b61
feat(agentic-org): slice 2 — supervisor triage action resolver (North…
maximdolphin May 30, 2026
2c2e0f9
feat(agentic-org): slice 3 — agent-native knowledge graph projection …
maximdolphin May 30, 2026
61ddf57
feat(agentic-org): slice 4 — wire observe.ts to real work-item state
maximdolphin May 30, 2026
06e3cdf
feat(agentic-org): slice 5 — review board as a real gate
maximdolphin May 30, 2026
e2c1e4a
docs(agentic-org): slice 6 — doc coherence (status frontmatter + Nort…
maximdolphin May 30, 2026
fe8128b
fix(agentic-org): MD018 reflow in NORTH_STAR_ALIGNMENT_CHECKPOINT
claude May 30, 2026
7568d23
fix(agentic-org): install @nats-io v3 + pg deps — unblocks workers te…
maximdolphin May 30, 2026
d454c1f
feat(agentic-org): Phase 3 — deterministic keep-alive (org + agent li…
maximdolphin May 30, 2026
e19a8de
feat(agentic-org): Phase 4 — Hermes runtime + Hindsight memory + orch…
maximdolphin May 30, 2026
33e40d0
feat(agentic-org): Phase 5 — bootable process host + container substr…
maximdolphin May 30, 2026
c019a1d
feat(agentic-org): wire deterministic keep-alive as a third worker-ru…
maximdolphin May 30, 2026
d9c5a97
feat(agentic-org): make the deterministic keep-alive real — Cockroach…
maximdolphin May 30, 2026
4ac430c
docs(agentic-org): checkpoint — deterministic keep-alive control plan…
maximdolphin May 30, 2026
3733717
feat(agentic-org): k8s deploy substrate — cockroach + nats + worker m…
maximdolphin May 30, 2026
2856bc5
feat(agentic-org): k8s deadline tuning + spin-up-task publisher
maximdolphin May 30, 2026
cdf945d
docs(agentic-org): Phase 6 checkpoint — running in kubernetes-in-dock…
maximdolphin May 30, 2026
82c3d06
feat(agentic-org): agent liveness is real — second half of keep-alive…
maximdolphin May 30, 2026
c934313
docs(agentic-org): Phase 7 checkpoint — agent liveness real, both hal…
maximdolphin May 30, 2026
02e5c83
feat(agentic-org): wire the orchestration's Hermes heartbeat to the a…
maximdolphin May 30, 2026
22efcd8
docs(agentic-org): consolidation + honest status — keep-alive tenet #…
maximdolphin May 30, 2026
65b9170
feat(agentic-org): integrate the Hermes data plane into the deployed …
maximdolphin May 30, 2026
7ba4507
docs(agentic-org): Phase 9 capstone — autonomous data plane runs end-…
maximdolphin May 30, 2026
2e8c435
docs(agentic-org): the full watch loop closes in k8s — keep-alive cau…
maximdolphin May 30, 2026
2e1e984
fix(lint): MD032 blanks-around-lists in NORTH_STAR_ALIGNMENT_CHECKPOI…
claude May 30, 2026
f6d1d12
feat(agentic-org): independent fast keep-alive loop — decouple the he…
maximdolphin May 30, 2026
711b7f5
docs(agentic-org): independent keep-alive loop proven in k8s — heartb…
maximdolphin May 30, 2026
7bbb9d3
feat(agentic-org): durable Cockroach-backed Hindsight memory, wired i…
maximdolphin May 30, 2026
ac0d040
feat(agentic-org): durable Cockroach-backed Hermes runs, wired into t…
maximdolphin May 30, 2026
4bed8cc
fix(agentic-org): durable Hermes/memory id-collision + JSONB cast (ca…
maximdolphin May 30, 2026
286cbc0
docs(agentic-org): durable data plane runs to completion in k8s; live…
maximdolphin May 30, 2026
81c3df6
fix(markdownlint): MD032 blank lines around two lists in NORTH_STAR c…
claude May 30, 2026
3383ebe
feat(agentic-org): composed organization reaction-plan executor (agen…
maximdolphin May 30, 2026
4d838db
feat(workers): produce durable org artifacts in deployed worker
maximdolphin May 30, 2026
697059b
docs: record Phase 12 org-artifact command pipeline proven in-cluster
maximdolphin May 30, 2026
968147f
feat(application): agent decisions computed by the deterministic kernel
maximdolphin May 30, 2026
6f3a3a8
docs: record Phase 13 computed agent decision proven in-cluster
maximdolphin May 30, 2026
5a2f908
docs: record operator tenet #1 holistic keep-alive proof (org v594, 1…
maximdolphin May 30, 2026
f1055f2
feat: live LLM decision backend + real sandboxed tool execution
maximdolphin May 30, 2026
c2dd159
docs: record Phase 14 live LLM + sandboxed-tool backend proven in-clu…
maximdolphin May 30, 2026
bcace47
fix(lint): clear markdownlint MD032/MD026 in NORTH_STAR_ALIGNMENT_CHE…
claude May 30, 2026
b8fa461
fix(review): resolve all 7 Copilot review findings on PR #6071
maximdolphin May 30, 2026
711536e
feat(org): P0 blueprint + P1 org structure as data (16 depts + ~115 h…
maximdolphin May 30, 2026
808d3cb
feat(org): P2 hat binding lifecycle + expiry + succession + OrgEvent …
maximdolphin May 30, 2026
26ae95b
feat(org): P3 prioritization (directors/TPMs) + RMO hat-supply voting
maximdolphin May 30, 2026
960d6da
feat(org): P4 assignment engine (rank by reputation, assign within su…
maximdolphin May 30, 2026
82e9fd1
feat(org): P5 work pipeline driver (customer discovery -> release)
maximdolphin May 30, 2026
5682fa5
feat(org): P6 observability — org snapshot + Cockroach org_events/hat…
maximdolphin May 30, 2026
5fe5c83
feat(org): P7a org runtime — full end-to-end cycle ties all layers
maximdolphin May 30, 2026
2c363b1
feat(org): P7 end-to-end org cycle proven in kind — full hierarchy to…
maximdolphin May 30, 2026
7e77842
docs: record P7 — full hat+department org proven end-to-end in kind (…
maximdolphin May 30, 2026
e707441
fix(lint): clear markdownlint MD022 on P7 checkpoint heading
maximdolphin May 30, 2026
d469f5c
docs: design the dynamic memory system (hat+agent+work memory, weight…
maximdolphin May 30, 2026
6c0dec1
fix(agentic-org): unblock markdownlint — reflow line-leading `+` in O…
claude May 30, 2026
4bfb99c
docs(memory): add retrieval/storage reliability model + Hindsight int…
maximdolphin May 30, 2026
12597af
docs(memory): close 5 design gaps + ground Hindsight integration in i…
maximdolphin May 30, 2026
f8cce07
docs(work-os): W0 — gap audit + overhaul design for a true agentic Wo…
maximdolphin May 30, 2026
8a72a46
fix(agentic-org): close 2 Copilot P1 review findings on #6071
May 30, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions agentic-organization/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
node_modules
**/*.test.ts
docs
.git
.gitignore
*.md
deploy
26 changes: 26 additions & 0 deletions agentic-organization/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Agentic Organization worker runtime.
#
# The code runs directly via `node --experimental-strip-types` (no build step,
# no bundler) per the repo convention. node:24-slim (Debian) is used over Alpine
# so the `pg` and @nats-io native paths resolve against glibc cleanly.
FROM node:24-slim

WORKDIR /app

# Install only production deps first for layer caching. package-lock.json is the
# pinned dependency graph (@nats-io/jetstream, @nats-io/transport-node, pg).
COPY package.json package-lock.json ./
RUN npm ci --omit=dev

# Copy the source. No compile — strip-types runs the .ts directly.
COPY tsconfig.json ./
COPY packages ./packages
COPY apps ./apps

# Run as the non-root node user (defense in depth; the worker needs no root).
USER node

# The worker is a long-running process driven by the always-on loop. SIGTERM is
# handled by the entrypoint (graceful shutdown of cockroach + nats ports).
ENV NODE_ENV=production
ENTRYPOINT ["node", "--experimental-strip-types", "apps/workers/src/main.ts"]
64 changes: 64 additions & 0 deletions agentic-organization/apps/workers/src/adapters/ollama-chat-port.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/**
* Ollama chat adapter — a real ChatCompletionPort backed by a model served by
* Ollama (https://ollama.com). Runs entirely in-cluster (no external
* credentials): the worker POSTs to the in-cluster Ollama service and the model
* returns its choice. This is the agent's live decision backend.
*
* Bounded by an AbortController timeout so a slow/hung model never stalls the
* agent run (the model-backed composer falls back to the deterministic policy
* when this throws — the agent stays alive).
*/

import type { ChatCompletionPort, ChatCompletionRequest } from "../../../../packages/application/src/index.ts";

export type CreateOllamaChatPortInput = {
baseUrl: string;
model: string;
timeoutMs?: number;
/** injected for testability; defaults to global fetch */
fetchImpl?: typeof fetch;
};

type OllamaChatResponse = {
message?: { content?: string };
};

export function createOllamaChatPort(input: CreateOllamaChatPortInput): ChatCompletionPort {
const fetchImpl = input.fetchImpl ?? fetch;
const timeoutMs = input.timeoutMs ?? 20_000;
const url = `${input.baseUrl.replace(/\/+$/, "")}/api/chat`;

return {
complete: async (request: ChatCompletionRequest): Promise<string> => {
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), timeoutMs);
try {
const response = await fetchImpl(url, {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({
model: input.model,
stream: false,
options: { temperature: 0 },
messages: [
{ role: "system", content: request.system },
{ role: "user", content: request.user },
],
}),
signal: controller.signal,
});
if (!response.ok) {
throw new Error(`ollama chat failed: ${response.status} ${response.statusText}`);
}
const body = (await response.json()) as OllamaChatResponse;
const content = body.message?.content;
if (typeof content !== "string") {
throw new Error("ollama chat response had no message content");
}
return content;
} finally {
clearTimeout(timer);
}
},
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/**
* Subprocess sandbox adapter — a real SandboxToolPort that runs a tool as a
* bounded, isolated child process:
* - executed in a throwaway temp dir (isolated cwd),
* - with a stripped environment (only PATH), so the tool cannot read worker
* secrets/config,
* - killed (SIGKILL) on timeout, with output size capped,
* - never inherits the parent stdio.
*
* Result-as-DU: failures (non-zero exit, timeout, spawn error) come back as
* { ok:false, reason } — the agent run treats tool failure as supplementary,
* never fatal.
*/

import { execFile } from "node:child_process";
import { mkdtempSync, rmSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";

import type { SandboxToolPort, SandboxToolRequest, SandboxToolResult } from "../../../../packages/application/src/index.ts";

const MAX_OUTPUT_BYTES = 64 * 1024;

/** POSIX "/..." or Windows "C:\..." / "C:/...". */
function isAbsolutePath(command: string): boolean {
return command.startsWith("/") || /^[A-Za-z]:[\\/]/.test(command);
}

export function createSubprocessSandbox(): SandboxToolPort {
return {
run: async (request: SandboxToolRequest): Promise<SandboxToolResult> => {
// The contract requires an absolute command path. A relative command would
// be resolved via PATH and could execute an unexpected binary, so reject
// it as a Result rather than spawning it.
if (!isAbsolutePath(request.command)) {
return { ok: false, reason: `sandbox command must be an absolute path, got '${request.command}'` };
}
const workdir = mkdtempSync(join(tmpdir(), "agentic-sandbox-"));
try {
Comment thread
maximdolphin marked this conversation as resolved.
Comment thread
maximdolphin marked this conversation as resolved.
Comment thread
maximdolphin marked this conversation as resolved.
return await new Promise<SandboxToolResult>((resolve) => {
execFile(
request.command,
[...request.args],
{
cwd: workdir,
timeout: request.timeoutMs,
killSignal: "SIGKILL",
maxBuffer: MAX_OUTPUT_BYTES,
encoding: "utf8",
// stripped env: only PATH, so the tool cannot read worker secrets
env: { PATH: process.env["PATH"] ?? "/usr/local/bin:/usr/bin:/bin" },
windowsHide: true,
},
(error, stdout) => {
if (error !== null) {
resolve({ ok: false, reason: error.message });
return;
}
resolve({ ok: true, stdout });
},
);
});
} catch (error) {
return { ok: false, reason: error instanceof Error ? error.message : String(error) };
} finally {
rmSync(workdir, { recursive: true, force: true });
}
},
};
}
4 changes: 4 additions & 0 deletions agentic-organization/apps/workers/src/composition.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { KeepAliveLane } from "../../../packages/keepalive/src/index.ts";
import type { NatsJetStreamEventConsumer } from "../../../packages/messaging-nats/src/index.ts";
import type { OrganizationWorkerHost } from "../../../packages/workers/src/index.ts";
import {
Expand All @@ -11,6 +12,8 @@ export type WorkerRuntimePorts = {
organizationWorkerHost: OrganizationWorkerHost;
natsEventConsumer: NatsJetStreamEventConsumer;
telemetrySink: WorkerRuntimeTelemetrySink;
/** optional so in-memory composition paths can omit the durable keep-alive lane */
keepAliveLane?: KeepAliveLane;
};

export type ComposeWorkerRuntimeInput = {
Expand All @@ -24,5 +27,6 @@ export function composeWorkerRuntime(input: ComposeWorkerRuntimeInput): WorkerRu
organizationWorkerHost: input.ports.organizationWorkerHost,
natsEventConsumer: input.ports.natsEventConsumer,
telemetrySink: input.ports.telemetrySink,
...(input.ports.keepAliveLane === undefined ? {} : { keepAliveLane: input.ports.keepAliveLane }),
});
}
67 changes: 67 additions & 0 deletions agentic-organization/apps/workers/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,17 @@ import { WorkerRuntimeConfigError, WorkerRuntimeConfigErrorCode, type WorkerRunt

const decimalIntegerPattern = /^[0-9]+$/;

/**
* Default deadline (ms) past which the deterministic keep-alive engine treats
* the org as flatlining and raises a self-heal alert. Optional env override;
* defaulted so existing deployments do not need a new variable.
*/
export const WorkerKeepAliveConfigDefault = {
OrgHeartbeatDeadlineMs: 30_000,
/** cadence of the independent keep-alive loop (decoupled from the work cycle) */
LoopIntervalMs: 5_000,
} as const;

export const WorkerProcessEnvName = {
AgenticOrgEnv: "AGENTIC_ORG_ENV",
AgenticOrgId: "AGENTIC_ORG_ID",
Expand All @@ -14,6 +25,10 @@ export const WorkerProcessEnvName = {
WorkerOutboxBatchSize: "WORKER_OUTBOX_BATCH_SIZE",
WorkerReactionPlanBatchSize: "WORKER_REACTION_PLAN_BATCH_SIZE",
WorkerReactionPlanLeaseMs: "WORKER_REACTION_PLAN_LEASE_MS",
WorkerKeepAliveOrgHeartbeatDeadlineMs: "WORKER_KEEP_ALIVE_ORG_HEARTBEAT_DEADLINE_MS",
/** when set, the agent's composer makes real model calls to this in-cluster endpoint */
LlmBaseUrl: "LLM_BASE_URL",
LlmModel: "LLM_MODEL",
} as const;

export type WorkerProcessEnvName = (typeof WorkerProcessEnvName)[keyof typeof WorkerProcessEnvName];
Expand All @@ -27,6 +42,11 @@ export type WorkerDurableRuntimeConfig = {
workerOutboxBatchSize: number;
workerReactionPlanBatchSize: number;
workerReactionPlanLeaseMs: number;
workerKeepAliveOrgHeartbeatDeadlineMs: number;
/** in-cluster model endpoint for the agent's decision backend (optional) */
llmBaseUrl?: string;
/** model name to ask the endpoint for (optional; required when llmBaseUrl is set) */
llmModel?: string;
};

export type WorkerProcessConfig = WorkerRuntimeConfig & WorkerDurableRuntimeConfig;
Expand Down Expand Up @@ -66,9 +86,56 @@ export function parseWorkerRuntimeConfigFromEnv(env: WorkerProcessEnvironment):
env[WorkerProcessEnvName.WorkerReactionPlanBatchSize],
),
workerReactionPlanLeaseMs: parseWorkerReactionPlanLeaseMs(env[WorkerProcessEnvName.WorkerReactionPlanLeaseMs]),
workerKeepAliveOrgHeartbeatDeadlineMs: parseWorkerKeepAliveOrgHeartbeatDeadlineMs(
env[WorkerProcessEnvName.WorkerKeepAliveOrgHeartbeatDeadlineMs],
),
// optional model backend — only set when both URL and model are provided
...parseLlmConfig(env),
};
}

function parseLlmConfig(env: WorkerProcessEnvironment): { llmBaseUrl?: string; llmModel?: string } {
const baseUrl = nonEmpty(env[WorkerProcessEnvName.LlmBaseUrl]);
const model = nonEmpty(env[WorkerProcessEnvName.LlmModel]);
if (baseUrl === undefined && model === undefined) {
// neither set → the deterministic composer is used (a valid, intended mode)
return {};
Comment thread
maximdolphin marked this conversation as resolved.
Comment thread
maximdolphin marked this conversation as resolved.
Comment thread
maximdolphin marked this conversation as resolved.
}
if (baseUrl === undefined || model === undefined) {
// exactly one set → a misconfiguration; fail loudly rather than silently
// dropping the model backend, which would be hard to diagnose in-cluster.
throw new WorkerRuntimeConfigError(WorkerRuntimeConfigErrorCode.PartialLlmConfig);
}
return { llmBaseUrl: baseUrl, llmModel: model };
}

function nonEmpty(value: string | undefined): string | undefined {
const trimmed = value?.trim();
return trimmed !== undefined && trimmed.length > 0 ? trimmed : undefined;
}

function parseWorkerKeepAliveOrgHeartbeatDeadlineMs(value: string | undefined): number {
return parseOptionalPositiveDecimalInteger(
value,
WorkerKeepAliveConfigDefault.OrgHeartbeatDeadlineMs,
WorkerRuntimeConfigErrorCode.InvalidWorkerKeepAliveOrgHeartbeatDeadlineMs,
);
}

function parseOptionalPositiveDecimalInteger(
value: string | undefined,
defaultValue: number,
errorCode: WorkerRuntimeConfigErrorCode,
): number {
const trimmedValue = value?.trim();

if (trimmedValue === undefined || trimmedValue.length === 0) {
return defaultValue;
}

return parsePositiveDecimalInteger(trimmedValue, errorCode);
}

function readRequiredEnvValue(
env: WorkerProcessEnvironment,
name: WorkerProcessEnvName,
Expand Down
35 changes: 35 additions & 0 deletions agentic-organization/apps/workers/src/durable-composition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,13 @@ import {
type EventPayloadHashCalculator,
type ReactionPlanActionExecutorPort,
} from "../../../packages/runtime/src/index.ts";
import { createKeepAliveLane, type KeepAliveLane } from "../../../packages/keepalive/src/index.ts";
import { InboundEventConsumerName } from "../../../packages/state/src/index.ts";
import {
createCockroachControlPlaneStateStore,
createCockroachDurableStateAdapters,
createCockroachKeepAliveActionSink,
createCockroachKeepAliveSnapshotSource,
type CockroachOrganizationSqlExecutor,
} from "../../../packages/state-cockroach/src/index.ts";
import {
Expand Down Expand Up @@ -49,6 +53,7 @@ export type DurableWorkerRuntimePorts = {
organizationWorkerHost: OrganizationWorkerHost;
natsEventConsumer: NatsJetStreamEventConsumer;
telemetrySink: WorkerRuntimeTelemetrySink;
keepAliveLane: KeepAliveLane;
};

export type ComposeDurableWorkerRuntimePortsInput = {
Expand Down Expand Up @@ -92,6 +97,7 @@ export function composeDurableWorkerRuntimePorts(
eventIngestionProcessor,
deadLetterPublisher: input.durableAdapters.natsDeadLetterPublisher,
});
const keepAliveLane = composeDurableKeepAliveLane(input);

return {
organizationWorkerHost: createOrganizationWorkerHost({
Expand All @@ -104,5 +110,34 @@ export function composeDurableWorkerRuntimePorts(
}),
natsEventConsumer,
telemetrySink: input.durableAdapters.telemetrySink,
keepAliveLane,
};
}

/**
* Compose the deterministic keep-alive control plane on durable Cockroach state:
* a control-plane store (org proof-of-life + alert log) -> snapshot source ->
* action sink -> lane. The lane ticks the org heartbeat every worker cycle and
* routes self-heal signals to durable state — the operator's #1 tenet, real.
*/
function composeDurableKeepAliveLane(input: ComposeDurableWorkerRuntimePortsInput): KeepAliveLane {
const controlPlaneStore = createCockroachControlPlaneStateStore({
executor: input.durableAdapters.cockroachExecutor,
});

return createKeepAliveLane({
source: createCockroachKeepAliveSnapshotSource({
store: controlPlaneStore,
organizationId: input.config.organizationId,
orgHeartbeatDeadlineMs: input.config.workerKeepAliveOrgHeartbeatDeadlineMs,
// the engine measures org age via the DB clock; this clock only feeds the
// (v1-empty) lease-expiry branch — derive epoch ms from the injected ISO now
clock: { now: () => Date.parse(input.runtimeUtilities.now()) },
}),
sink: createCockroachKeepAliveActionSink({
store: controlPlaneStore,
organizationId: input.config.organizationId,
generateAlertId: () => input.runtimeUtilities.createId("ctrl-alert"),
}),
});
}
15 changes: 15 additions & 0 deletions agentic-organization/apps/workers/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export {
WorkerKeepAliveConfigDefault,
WorkerProcessEnvName,
parseWorkerRuntimeConfigFromEnv,
type WorkerDurableRuntimeConfig,
Expand Down Expand Up @@ -93,6 +94,8 @@ export {
WorkerRuntimeTelemetryEventName,
createWorkerRuntime,
type CreateWorkerRuntimeInput,
type WorkerKeepAliveLane,
type WorkerKeepAliveLaneResult,
type WorkerRuntime,
type WorkerRuntimeConfig,
type WorkerRuntimeFailure,
Expand Down Expand Up @@ -161,3 +164,15 @@ export {
createCockroachWorkItemStateHistoryMetadataMigration,
type CockroachAnySqlStatement,
} from "../../../packages/state-cockroach/src/index.ts";
export {
WorkerMainDefault,
WorkerMainLogStream,
runMain,
type RunMainDependencies,
type WorkerMainClock,
type WorkerMainConstructors,
type WorkerMainDurablePorts,
type WorkerMainLogRecord,
type WorkerMainLogger,
type WorkerMainSignalRegistrar,
} from "./main.ts";
Loading
Loading