From 814509d292b2127f0f6afeb0534e4d5eeff7f590 Mon Sep 17 00:00:00 2001 From: Sawyer Cutler Date: Mon, 21 Sep 2026 22:45:39 -0700 Subject: [PATCH 1/5] test(distiller): assert a mail trigger, not schedule/cron createResidentDistiller should address itself via a mail trigger (type: "mail", to:
) instead of the reserved, unimplemented schedule/cron trigger. Red until the implementation catches up. --- src/distiller/workflow.test.ts | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/distiller/workflow.test.ts b/src/distiller/workflow.test.ts index 7c52fb4..86c18a0 100644 --- a/src/distiller/workflow.test.ts +++ b/src/distiller/workflow.test.ts @@ -8,8 +8,9 @@ import { SIDECAR_BUNDLE_ID } from "../sidecar-bundle.ts"; import { createResidentDistiller } from "./workflow.ts"; describe("createResidentDistiller", () => { - it("returns a schedule workflow with memory tools on the agent", () => { + it("returns a mail-triggered workflow with memory tools on the agent", () => { const { workflow, agent, generatorAgentId } = createResidentDistiller({ + mailTo: "resident-distiller@tenant.example.com", inference: { sources: [{ provider: "openai", model: "gpt-4.1-mini" }], }, @@ -18,7 +19,7 @@ describe("createResidentDistiller", () => { expect(generatorAgentId).toBe(RESIDENT_DISTILLER_AGENT_ID); expect(workflow.id).toBe(RESIDENT_DISTILLER_WORKFLOW_ID); expect(workflow.triggers).toEqual([ - { type: "schedule", cron: "*/5 * * * *" }, + { type: "mail", to: "resident-distiller@tenant.example.com" }, ]); expect(agent.id).toBe(RESIDENT_DISTILLER_AGENT_ID); // One factory: the memory sidecar bundle carries every memory tool. @@ -29,11 +30,11 @@ describe("createResidentDistiller", () => { expect(agent.systemPrompt).toContain(RESIDENT_DISTILLER_AGENT_ID); }); - it("allows cron and id overrides", () => { + it("allows mailTo and id overrides", () => { const { workflow, generatorAgentId, agent } = createResidentDistiller({ id: "my-distiller", agentId: "my-agent", - cron: "0 * * * *", + mailTo: "my-agent@acme.example.com", inference: { sources: [{ provider: "openai", model: "gpt-4.1-mini" }], }, @@ -41,10 +42,18 @@ describe("createResidentDistiller", () => { expect(workflow.id).toBe("my-distiller"); expect(generatorAgentId).toBe("my-agent"); expect(workflow.triggers[0]).toEqual({ - type: "schedule", - cron: "0 * * * *", + type: "mail", + to: "my-agent@acme.example.com", }); expect(agent.systemPrompt).toContain("my-agent"); expect(agent.systemPrompt).not.toContain(RESIDENT_DISTILLER_AGENT_ID); }); + + it("does not carry a cron/schedule field in its public options", () => { + const opts: import("./workflow.ts").CreateResidentDistillerOpts = { + mailTo: "resident-distiller@tenant.example.com", + inference: { sources: [{ provider: "openai", model: "gpt-4.1-mini" }] }, + }; + expect("cron" in opts).toBe(false); + }); }); From 4c3a39e69a6884ecb869e488b3b904c4b951a045 Mon Sep 17 00:00:00 2001 From: Sawyer Cutler Date: Mon, 21 Sep 2026 22:46:00 -0700 Subject: [PATCH 2/5] build(deps): move @intx/* to 0.4.0 (CL-8797) Keeps each dependency's existing caret range style. --- bun.lock | 44 ++++++++++++++++++++++---------------------- package.json | 12 ++++++------ 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/bun.lock b/bun.lock index 11b39e3..f385f95 100644 --- a/bun.lock +++ b/bun.lock @@ -5,12 +5,12 @@ "": { "name": "company-knowledge-engine", "dependencies": { - "@intx/agent": "^0.3.0", - "@intx/authz": "^0.3.0", - "@intx/hub-api": "^0.3.0", - "@intx/log": "^0.3.0", - "@intx/types": "^0.3.0", - "@intx/workflow": "^0.3.0", + "@intx/agent": "^0.4.0", + "@intx/authz": "^0.4.0", + "@intx/hub-api": "^0.4.0", + "@intx/log": "^0.4.0", + "@intx/types": "^0.4.0", + "@intx/workflow": "^0.4.0", "arktype": "^2.1.29", "drizzle-orm": "^0.45.1", "hono": "^4.9.0", @@ -50,37 +50,37 @@ "@hono/standard-validator": ["@hono/standard-validator@0.2.3", "", { "peerDependencies": { "@standard-schema/spec": "^1.0.0", "hono": ">=3.9.0" } }, "sha512-bp9vHu6Va6SfMHC3D4ZLBbT/woi+AZ9CRdTXQu3kLJuLh2W/Gb9UO4hijS+BQAGFXi4EGpXdetxpzwTAawSVeg=="], - "@intx/agent": ["@intx/agent@0.3.0", "", { "dependencies": { "@intx/inference": "0.3.0", "@intx/log": "0.3.0", "@intx/mime": "0.3.0", "@intx/types": "0.3.0", "arktype": "^2.1.29" } }, "sha512-a7cgmH8FSsGQ7BpLKQhEwZYRfofWh3lWEGgKFsk53zdgjndtDfqAf2I64QMPAqC2Y2Npag/z1NA5lEsIqAGvPg=="], + "@intx/agent": ["@intx/agent@0.4.0", "", { "dependencies": { "@intx/inference": "0.4.0", "@intx/log": "0.4.0", "@intx/mime": "0.4.0", "@intx/types": "0.4.0", "arktype": "^2.1.29" } }, "sha512-qBlqDYnsaRMsug/lEKwUvPgQfjiwppTpfw5JaUh6pwKi0dGvckv3ugjJvLdHM052nTFMgLgOwo1LvbRjPZ5Uwg=="], - "@intx/authz": ["@intx/authz@0.3.0", "", { "dependencies": { "@intx/types": "0.3.0" } }, "sha512-kyIKQAVjfB8H84mES0QA4cNnYfpPoyLmQITVBxiuXv1VO/K74TQZnCDpoo0IL7oFk2q7bbDXSAEE4ubMBVTHzA=="], + "@intx/authz": ["@intx/authz@0.4.0", "", { "dependencies": { "@intx/types": "0.4.0" } }, "sha512-A9x4EzcECnFjhDoqj0XjaOb1GaxRyJucXOuIbY+fcPluUuMCGFvExD6DJZwjJmIYdeCvL8i96gPkncu/fAR9qA=="], - "@intx/crypto": ["@intx/crypto@0.3.0", "", { "dependencies": { "@intx/types": "0.3.0" } }, "sha512-NsRzvkFGb0Pcsm9uLFFSXNl6Cbu+ii6VkYAw81qs9IbZzbAFfsZSUVQaX6EZuPNyJ8KK4KmBtqmioq1mhXsJww=="], + "@intx/crypto": ["@intx/crypto@0.4.0", "", { "dependencies": { "@intx/types": "0.4.0" } }, "sha512-4/qWypC90GevbV9u1i/93tn46jsXhj8wE1Pn+awg8/ECpwhHnhPLT5Uy423Arr9eGmRmF6HiMyXcEgH1Z9/Rkw=="], - "@intx/db": ["@intx/db@0.3.0", "", { "dependencies": { "@intx/authz": "0.3.0", "@intx/crypto": "0.3.0", "@intx/log": "0.3.0", "@intx/types": "0.3.0", "arktype": "^2.1.29", "drizzle-orm": "^0.45.1", "postgres": "^3.4.8" } }, "sha512-MXNeUVJTftQuSHj5zSUBQsUcFN3wUBs8t6yT6lqjbaNxpT1C7kGx8qXb95WuadZln+krlLhyoUwGMF7EmYvlnw=="], + "@intx/db": ["@intx/db@0.4.0", "", { "dependencies": { "@intx/authz": "0.4.0", "@intx/crypto": "0.4.0", "@intx/hub-common": "0.4.0", "@intx/log": "0.4.0", "@intx/types": "0.4.0", "arktype": "^2.1.29", "drizzle-orm": "^0.45.1", "postgres": "^3.4.8" } }, "sha512-B26emrRrpIAlRygTWs6akVA6V/rN07v4YRxj3iTxzAOJVayIHSmPuPmKxqKN/AsBgLq6H1q94RP9sq05yb4twg=="], - "@intx/hub-api": ["@intx/hub-api@0.3.0", "", { "dependencies": { "@hono/standard-validator": "^0.2.2", "@intx/agent": "0.3.0", "@intx/authz": "0.3.0", "@intx/crypto": "0.3.0", "@intx/db": "0.3.0", "@intx/hub-common": "0.3.0", "@intx/hub-sessions": "0.3.0", "@intx/log": "0.3.0", "@intx/mime": "0.3.0", "@intx/storage-isogit": "0.3.0", "@intx/types": "0.3.0", "@intx/workflow-deploy": "0.3.0", "arktype": "^2.1.29", "better-auth": "^1.4.18", "drizzle-orm": "^0.45.1", "hono": "^4.11.9", "hono-openapi": "^1.2.0", "isomorphic-git": "^1.27.2", "ssri": "^12.0.0" } }, "sha512-o3KuJilWywIjQ82q+t3kC5syHm/JCexnEYegngBZ7HD4lvbEoUkJnmhVUS5NxEFsr2Oqp0jEe4kpC96oJ2sKDA=="], + "@intx/hub-api": ["@intx/hub-api@0.4.0", "", { "dependencies": { "@hono/standard-validator": "^0.2.2", "@intx/agent": "0.4.0", "@intx/authz": "0.4.0", "@intx/crypto": "0.4.0", "@intx/db": "0.4.0", "@intx/hub-common": "0.4.0", "@intx/hub-sessions": "0.4.0", "@intx/log": "0.4.0", "@intx/mime": "0.4.0", "@intx/storage-isogit": "0.4.0", "@intx/types": "0.4.0", "@intx/workflow-deploy": "0.4.0", "arktype": "^2.1.29", "better-auth": "^1.4.18", "drizzle-orm": "^0.45.1", "hono": "^4.11.9", "hono-openapi": "^1.2.0", "isomorphic-git": "^1.27.2", "ssri": "^12.0.0" } }, "sha512-3Txw7Im38BdRujYeRlxgrzCdvOG1v92556AjNa/6WXSwgXt9Mn2fB4RoQrA6oUHcm10Y94WZh3IjaQsXFl7Qvg=="], - "@intx/hub-common": ["@intx/hub-common@0.3.0", "", { "dependencies": { "@intx/types": "0.3.0" } }, "sha512-dA8pTmBTu1JHGd3rGJrMsRWrai4GBBNnPxpZFFtXwQPzgL290lx2R+9BpRo2apdKbmgd+KOVshLvOdcUhAqghw=="], + "@intx/hub-common": ["@intx/hub-common@0.4.0", "", { "dependencies": { "@intx/types": "0.4.0" } }, "sha512-4dcRX3kamqduf1Yil85GVsjXKnAnu6uqSYrAsl4vGpuV6R2DCy7z/PHd+DtIqk6TJrRdW7DtfkNXwSEc3dn2VQ=="], - "@intx/hub-sessions": ["@intx/hub-sessions@0.3.0", "", { "dependencies": { "@intx/agent": "0.3.0", "@intx/crypto": "0.3.0", "@intx/db": "0.3.0", "@intx/hub-common": "0.3.0", "@intx/log": "0.3.0", "@intx/mime": "0.3.0", "@intx/pack-transport": "0.3.0", "@intx/storage-isogit": "0.3.0", "@intx/tool-packaging": "0.3.0", "@intx/types": "0.3.0", "@intx/workflow": "0.3.0", "@intx/workflow-deploy": "0.3.0", "arktype": "^2.1.29", "drizzle-orm": "^0.45.1", "isomorphic-git": "^1.27.2", "tar": "^7.5.1" } }, "sha512-L9B/vuQakvbj4CYrEhbNwu0z/S9/2jBXmaJdxaC1zfakbOiHya4HFW/YAZKAgOi7z0cpxFftsK/RN3Yyrd/+Wg=="], + "@intx/hub-sessions": ["@intx/hub-sessions@0.4.0", "", { "dependencies": { "@intx/agent": "0.4.0", "@intx/crypto": "0.4.0", "@intx/db": "0.4.0", "@intx/hub-common": "0.4.0", "@intx/log": "0.4.0", "@intx/mime": "0.4.0", "@intx/pack-transport": "0.4.0", "@intx/storage-isogit": "0.4.0", "@intx/tool-packaging": "0.4.0", "@intx/types": "0.4.0", "@intx/workflow": "0.4.0", "@intx/workflow-deploy": "0.4.0", "arktype": "^2.1.29", "drizzle-orm": "^0.45.1", "isomorphic-git": "^1.27.2", "tar": "^7.5.1" } }, "sha512-/3nd/B/gENy3lq+MA2AR95tBu3Rkkh176XM+A8/mNMGnolPBGw+1JBUGGJ8gvdvAfo64dwRcEs3BI/VD7zFlPQ=="], - "@intx/inference": ["@intx/inference@0.3.0", "", { "dependencies": { "@intx/log": "0.3.0", "@intx/types": "0.3.0", "arktype": "^2.1.29" } }, "sha512-2DxqWRp5cSziXgDXPomSy0HTLVesBCtZErsKXYFnliTwYM6U+GRKk5rzwWMMgMWMFbtUaiogPExcNQYBYmfjQA=="], + "@intx/inference": ["@intx/inference@0.4.0", "", { "dependencies": { "@intx/log": "0.4.0", "@intx/types": "0.4.0", "arktype": "^2.1.29" } }, "sha512-cuaqCqotmjg0OzGUm8QmFJr1xX5wPVS0LeuhrxHsj0X3ImoCzVB4e/ttTc+DaP3K1tTMQ/8Q8HHCAPX36mOecQ=="], - "@intx/log": ["@intx/log@0.3.0", "", { "dependencies": { "@logtape/hono": "^2.0.2", "@logtape/logtape": "^2.0.2" }, "peerDependencies": { "hono": "^4.0.0" }, "optionalPeers": ["hono"] }, "sha512-iooPSZjiEUO1A91X5STRhOAk+2RprliB4nbriV/dOOz86kuxZ60y5T8ISQ5Jaj1US870gntN6QwnefY38aWi2Q=="], + "@intx/log": ["@intx/log@0.4.0", "", { "dependencies": { "@logtape/hono": "^2.0.2", "@logtape/logtape": "^2.0.2" }, "peerDependencies": { "hono": "^4.0.0" }, "optionalPeers": ["hono"] }, "sha512-f1IPZ/9YpEqlA0I2UZPOlRJOTDoOFEZRwZoUVuw8DpgR1WatOMm4hA0E8o6Mtz+pA0ux7gVdls4y/JZcgypsfQ=="], - "@intx/mime": ["@intx/mime@0.3.0", "", { "dependencies": { "@intx/crypto": "0.3.0", "@intx/types": "0.3.0", "arktype": "^2.1.29" } }, "sha512-jpKZZpfWRQJ6fI8BEpHnr83N+1ZHrnOMY978B/6bgcjFn3qtm1f3KiR0yaQ8eF3r1VF327r3H2qiCCx0OFN9Ow=="], + "@intx/mime": ["@intx/mime@0.4.0", "", { "dependencies": { "@intx/crypto": "0.4.0", "@intx/types": "0.4.0", "arktype": "^2.1.29" } }, "sha512-sWrohF2uwVL5AZHbxIEUNiVUBhULff4XB7g6keCmyQWr296GKSvG/HmbihSXxiIvmmDzh9cl+6ZAJz/taxFNog=="], - "@intx/pack-transport": ["@intx/pack-transport@0.3.0", "", { "dependencies": { "@intx/types": "0.3.0" } }, "sha512-EQ1wM16323aIFhw3Ak6HwB8YqzKSAfRmJUwjIfqyXk2t6TGv4grws6dIs7Yau1dc372s/SO+GhvFaKgvI6XTWA=="], + "@intx/pack-transport": ["@intx/pack-transport@0.4.0", "", { "dependencies": { "@intx/types": "0.4.0" } }, "sha512-I+axd067ZFXaTRtr2zmBXl6/yU253wLc/YWEdXiPiqz06mIspR2BFJMbSXPzV4pM26n+1tv/9E5VNBQtdiYmSA=="], - "@intx/storage-isogit": ["@intx/storage-isogit@0.3.0", "", { "dependencies": { "@intx/log": "0.3.0", "@intx/mime": "0.3.0", "@intx/types": "0.3.0", "@isomorphic-git/lightning-fs": "4.7.0", "arktype": "^2.1.29", "buffer": "^6.0.3", "isomorphic-git": "^1.27.2" } }, "sha512-nzhl9WvxV66J1jjBfuAOjvwgiuS1DScnYomCPQrBxZNG35M5CYR3xyqR0RN0GfTj/7JlKWk6rF6Lu44aZDfzuw=="], + "@intx/storage-isogit": ["@intx/storage-isogit@0.4.0", "", { "dependencies": { "@intx/log": "0.4.0", "@intx/mime": "0.4.0", "@intx/types": "0.4.0", "@isomorphic-git/lightning-fs": "4.7.0", "arktype": "^2.1.29", "buffer": "^6.0.3", "isomorphic-git": "^1.27.2" } }, "sha512-3H4dhUsWmAixLEBp79vq9NVUf6Z4++pKzaODWFEgNfhLX2WeV5J/t6soUamL6T/8eok/SDgQ/sZiZMiJ5kDKOw=="], - "@intx/tool-packaging": ["@intx/tool-packaging@0.3.0", "", { "dependencies": { "@intx/agent": "0.3.0", "@intx/log": "0.3.0", "@intx/storage-isogit": "0.3.0", "@intx/types": "0.3.0", "arktype": "^2.1.29", "isomorphic-git": "^1.27.2", "npm-package-arg": "^12.0.2", "npm-pick-manifest": "^10.0.0", "npm-registry-fetch": "^19.0.0", "semver": "^7.7.2", "ssri": "^12.0.0", "tar": "^7.5.1" } }, "sha512-Lr/xdEjXTindJRm+eITvfeqpW/yl71thYjr3HXl41GJ9wpuOZPCjm9vBoRVKhUSwmIUKBYbm2VplXCCXaS7f4g=="], + "@intx/tool-packaging": ["@intx/tool-packaging@0.4.0", "", { "dependencies": { "@intx/agent": "0.4.0", "@intx/log": "0.4.0", "@intx/storage-isogit": "0.4.0", "@intx/types": "0.4.0", "arktype": "^2.1.29", "isomorphic-git": "^1.27.2", "npm-package-arg": "^12.0.2", "npm-pick-manifest": "^10.0.0", "npm-registry-fetch": "^19.0.0", "semver": "^7.7.2", "ssri": "^12.0.0", "tar": "^7.5.1" } }, "sha512-eBZIbGUcEBp0ppMCceA1PPd75LvXpUyWitqTIu7AsLxRNlU9gbE1hymWPXnhUKnt3LgSlHUi959Ehd6jG6mR7g=="], - "@intx/types": ["@intx/types@0.3.0", "", { "dependencies": { "arktype": "^2.1.29", "semver": "^7.7.2" } }, "sha512-PJ+v3IhtfZ4J7ZqJ8E39TteRMnC6Y503Q0JeCJdskkK+jhcjx01z7TJSozucagauAlpyh8Hn/9CyWFl53Ji0DQ=="], + "@intx/types": ["@intx/types@0.4.0", "", { "dependencies": { "arktype": "^2.1.29", "semver": "^7.7.2" } }, "sha512-nJ2fcmskMOZNMRfbHs5ueKpCANHNttoL+sZgIoFaVUF/QLpFWfVp0YV72CQAaa9bVv9j5kRSwtSOCCGSlwQ6Dw=="], - "@intx/workflow": ["@intx/workflow@0.3.0", "", { "dependencies": { "@intx/agent": "0.3.0", "@intx/inference": "0.3.0", "@intx/types": "0.3.0", "arktype": "^2.1.29" } }, "sha512-vaIqTohNNdCVhvZ4btWbIbpjp3140e5939tQP7t+rSkucTvnn6US+bXho1qUJyNQ577mf3YXHGgBCW8ppsnscA=="], + "@intx/workflow": ["@intx/workflow@0.4.0", "", { "dependencies": { "@intx/agent": "0.4.0", "@intx/inference": "0.4.0", "@intx/types": "0.4.0", "arktype": "^2.1.29" } }, "sha512-F5Is/lyKb4/WguAVYMDXwtI4ddUvqXbg34rcM6hPUOqupJHpbbD9+ZK/6TDfvbCiEgginbTVwMmNj6Fyg8vU+Q=="], - "@intx/workflow-deploy": ["@intx/workflow-deploy@0.3.0", "", { "dependencies": { "@intx/agent": "0.3.0", "@intx/tool-packaging": "0.3.0", "@intx/types": "0.3.0", "@intx/workflow": "0.3.0" } }, "sha512-eiCFS+e6DV9UTWFX5eINQCbXHi2w5Wn9SXtAOHZa4PIXOzxXKVJL/uXE/c6TfCVqhrsDdzYwrtt9koi5qmYXCg=="], + "@intx/workflow-deploy": ["@intx/workflow-deploy@0.4.0", "", { "dependencies": { "@intx/agent": "0.4.0", "@intx/tool-packaging": "0.4.0", "@intx/types": "0.4.0", "@intx/workflow": "0.4.0" } }, "sha512-TSLg9lPZvJ+leg2n0I/SWxZjcNQtzsH2oKLD04ptEsBZcbIuMINsQeZBmYV5Brdovy0J/SrWZyrOJ8lc+k/Fdw=="], "@isaacs/fs-minipass": ["@isaacs/fs-minipass@4.0.1", "", { "dependencies": { "minipass": "^7.0.4" } }, "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w=="], diff --git a/package.json b/package.json index 8845d4b..a37b8ae 100644 --- a/package.json +++ b/package.json @@ -51,12 +51,12 @@ "test:coverage": "bun test --coverage --coverage-reporter=lcov --coverage-reporter=text ./src" }, "dependencies": { - "@intx/agent": "^0.3.0", - "@intx/authz": "^0.3.0", - "@intx/hub-api": "^0.3.0", - "@intx/log": "^0.3.0", - "@intx/types": "^0.3.0", - "@intx/workflow": "^0.3.0", + "@intx/agent": "^0.4.0", + "@intx/authz": "^0.4.0", + "@intx/hub-api": "^0.4.0", + "@intx/log": "^0.4.0", + "@intx/types": "^0.4.0", + "@intx/workflow": "^0.4.0", "arktype": "^2.1.29", "drizzle-orm": "^0.45.1", "hono": "^4.9.0", From 28fb7c3b4b49963bedb79e43e130be017f2878f6 Mon Sep 17 00:00:00 2001 From: Sawyer Cutler Date: Mon, 21 Sep 2026 22:48:28 -0700 Subject: [PATCH 3/5] feat(distiller)!: run on a mail trigger instead of the unimplemented schedule trigger (CL-8798) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @intx/workflow's schedule trigger is reserved with no scheduler behind it — under 0.3.0 defineWorkflow accepted it silently and the workflow never ran; 0.4.0 now throws at defineWorkflow. corbits-memory owns no clock, so createResidentDistiller now defines a mail trigger instead: the deployed run fires on the first inbound mail at the address the host supplies. Ticking (deciding when to mail that address, e.g. via @corbits/cron) is entirely the host's responsibility. BREAKING CHANGE: CreateResidentDistillerOpts drops `cron` (optional, defaulted to every 5 minutes) and adds `mailTo` (required, the full mail address the workflow's run listens at). The resulting WorkflowDefinition's trigger is `{ type: "mail", to }` instead of `{ type: "schedule", cron }`. RESIDENT_DISTILLER_CRON_DEFAULT is removed; there is no replacement default since the address is host-specific (domain unknown to this package). --- src/distiller/constants.ts | 3 --- src/distiller/index.ts | 4 ++-- src/distiller/workflow.ts | 23 +++++++++++++++-------- src/index.ts | 1 - 4 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/distiller/constants.ts b/src/distiller/constants.ts index ba9dea0..d408d85 100644 --- a/src/distiller/constants.ts +++ b/src/distiller/constants.ts @@ -1,8 +1,5 @@ /** Stable generator id for the resident distiller — use with feed excludeGenerator. */ export const RESIDENT_DISTILLER_AGENT_ID = "resident-distiller"; -/** Default schedule: every 5 minutes. */ -export const RESIDENT_DISTILLER_CRON_DEFAULT = "*/5 * * * *"; - /** Default workflow id when host does not override. */ export const RESIDENT_DISTILLER_WORKFLOW_ID = "resident-memory-distiller"; diff --git a/src/distiller/index.ts b/src/distiller/index.ts index 4f63e78..15f85fb 100644 --- a/src/distiller/index.ts +++ b/src/distiller/index.ts @@ -4,7 +4,8 @@ * Two ways to run: * * 1. **Workflow** (recommended on Interchange): - * `createResidentDistiller({ inference })` → deploy the workflow. + * `createResidentDistiller({ mailTo, inference })` → deploy the + * workflow, then have the host mail `mailTo` on a schedule to tick it. * * 2. **Imperative tick** (any scheduler): * `runDistillTick({ client, distill, after })` with your model in `distill`. @@ -14,7 +15,6 @@ */ export { RESIDENT_DISTILLER_AGENT_ID, - RESIDENT_DISTILLER_CRON_DEFAULT, RESIDENT_DISTILLER_WORKFLOW_ID, } from "./constants.ts"; diff --git a/src/distiller/workflow.ts b/src/distiller/workflow.ts index f649f5e..0013117 100644 --- a/src/distiller/workflow.ts +++ b/src/distiller/workflow.ts @@ -5,10 +5,12 @@ * import { createResidentDistiller } from "@corbits/memory/distiller"; * * const workflow = createResidentDistiller({ + * mailTo: "resident-distiller@tenant.example.com", * inference: { sources: [{ provider: "openai", model: "gpt-4.1-mini" }] }, * }); * // deploy with host workflow-deploy; the host binds the `hub` credential - * // handle the sidecar bundle resolves at run time + * // handle the sidecar bundle resolves at run time, and ticks the workflow + * // by mailing `mailTo` (e.g. a @corbits/cron schedule) — see the README. * ``` */ import { @@ -24,7 +26,6 @@ import { memory } from "../sidecar-bundle.ts"; import { capabilityIdsForSurface } from "../grant-requirements.ts"; import { RESIDENT_DISTILLER_AGENT_ID, - RESIDENT_DISTILLER_CRON_DEFAULT, RESIDENT_DISTILLER_WORKFLOW_ID, } from "./constants.ts"; @@ -52,8 +53,13 @@ export type CreateResidentDistillerOpts = { id?: string; /** Agent id / generatorAgentId (default resident-distiller). */ agentId?: string; - /** Cron schedule (default every 5 minutes). */ - cron?: string; + /** + * The mail address this workflow's run is triggered at — the first + * inbound mail here fires the deployment's stable top-level run. The + * host owns ticking: mail this address on whatever cadence it wants + * (e.g. a `@corbits/cron` schedule), see the README. + */ + mailTo: string; /** Host inference preferences (required for deploy hashing). */ inference: { sources: readonly InferencePreference[] }; /** Override system prompt. */ @@ -74,8 +80,9 @@ export type ResidentDistiller = { }; /** - * Build a schedule-triggered workflow + agent preloaded with memory tools. - * Host supplies inference sources and deploys with memory* env credentials. + * Build a mail-triggered workflow + agent preloaded with memory tools. Host + * supplies inference sources and `mailTo`, and deploys with memory* env + * credentials. Ticking (deciding when to mail `mailTo`) is the host's job. */ export function createResidentDistiller( opts: CreateResidentDistillerOpts, @@ -105,8 +112,8 @@ export function createResidentDistiller( const workflow = defineWorkflow({ id: opts.id ?? RESIDENT_DISTILLER_WORKFLOW_ID, trigger: { - type: "schedule", - cron: opts.cron ?? RESIDENT_DISTILLER_CRON_DEFAULT, + type: "mail", + to: opts.mailTo, }, agent, }); diff --git a/src/index.ts b/src/index.ts index 1b77c36..9b6f161 100644 --- a/src/index.ts +++ b/src/index.ts @@ -154,7 +154,6 @@ export { // Resident distiller (CL-5869) — also `@corbits/memory/distiller` export { RESIDENT_DISTILLER_AGENT_ID, - RESIDENT_DISTILLER_CRON_DEFAULT, RESIDENT_DISTILLER_WORKFLOW_ID, buildDistilledClaim, createResidentDistiller, From 8095dfd3714726b3c94ca752203f6e8a7ed31178 Mon Sep 17 00:00:00 2001 From: Sawyer Cutler Date: Mon, 21 Sep 2026 22:50:15 -0700 Subject: [PATCH 4/5] docs(readme): document the distiller's mail trigger and host ticking Add a resident-distiller section with the new mailTo option and a host-generic example of ticking it (e.g. a @corbits/cron schedule whose delivery mails the distiller's address). Also fixes a missing TenantEnv import in the pre-existing workflow-memory mount example (caught while verifying every README ts fence compiles). --- README.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/README.md b/README.md index 6009b42..19b6c41 100644 --- a/README.md +++ b/README.md @@ -92,6 +92,7 @@ a tenant-session request: ```ts import { Hono } from "hono"; +import type { TenantEnv } from "@intx/hub-api"; import { mountWorkflowMemory, type Memory, @@ -137,6 +138,33 @@ docs. Details: [`docs/AUTHZ-DOCUMENT-ACCESS.md`](docs/AUTHZ-DOCUMENT-ACCESS.md). The resident distiller (`createResidentDistiller` / `runDistillTick`) is at `@corbits/memory/distiller`. +### Resident distiller + +`createResidentDistiller` returns a mail-triggered workflow + agent, preloaded +with the memory sidecar tools. It never ships a scheduler — the host owns +ticking: + +```ts +import { createResidentDistiller } from "@corbits/memory/distiller"; + +const { workflow, agent } = createResidentDistiller({ + mailTo: "resident-distiller@tenant.example.com", + inference: { sources: [{ provider: "openai", model: "gpt-4.1-mini" }] }, +}); +// deploy `workflow` (and `agent`) with the host's workflow-deploy; the run +// fires on the first inbound mail at `mailTo` and stays live for the host +// to keep addressing. +``` + +Ticking is a host concern, not this package's: point a scheduler at +`mailTo` on whatever cadence you want. If the host already runs +`@corbits/cron`, wire a schedule whose delivery mails `mailTo` — the same +pattern a cron-ticked workflow uses everywhere on Interchange: the ticker +polls for due rows and hands each one to the host's mail transport, so a +mail-triggered workflow is ticked by addressing it directly. No import of +`@corbits/cron` is required here; see its own README for `mountCron` / +`createCronTicker` wiring. + ### Lower-level: in-process calls, no HTTP `app` is optional. Passing only `config` builds the plane without From 0b55fd9d7b0341358258e542f688da242e12997b Mon Sep 17 00:00:00 2001 From: Sawyer Cutler Date: Mon, 21 Sep 2026 22:57:46 -0700 Subject: [PATCH 5/5] docs: changelog and DISTILLER.md for the distiller's mail trigger (CL-8798) --- CHANGELOG.md | 8 ++++++++ docs/DISTILLER.md | 6 +++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index facf1f0..8379770 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -65,6 +65,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- **Breaking:** `createResidentDistiller` runs on a `mail` trigger (CL-8798). + `CreateResidentDistillerOpts.cron` is replaced by a required `mailTo`, the + address the workflow's run is triggered at, and + `RESIDENT_DISTILLER_CRON_DEFAULT` is removed. The `schedule` trigger was + reserved with nothing behind it in `@intx/workflow`, so the distiller never + ticked, and 0.4.0 rejects it at `defineWorkflow`. Ticking is the host's job: + mail `mailTo` on a schedule, e.g. from `@corbits/cron`. +- `@intx/*` dependencies move to 0.4.0 (CL-8797). - **Product narrative:** default path is **add → ingest elements → process** (one host pipeline). Pull feed + `createResidentDistiller` are optional multi-writer / backfill process helpers, not the primary ingest story. diff --git a/docs/DISTILLER.md b/docs/DISTILLER.md index 0ac50e4..7a76af4 100644 --- a/docs/DISTILLER.md +++ b/docs/DISTILLER.md @@ -66,7 +66,7 @@ cursor = result.nextCursor; // persist Inference is **always injected** (`distill` callback or host agent sources). The package never embeds a model. -## Optional: schedule workflow scaffold (`createResidentDistiller`) +## Optional: mail-triggered workflow scaffold (`createResidentDistiller`) Scaffold for hosts that still want a deployed agent with memory tools + system prompt (loop-safety, access-tag copy). Prefer wiring **process next to @@ -76,6 +76,7 @@ add** in your ingest workflow; use this for backfill-style residency only. import { createResidentDistiller } from "@corbits/memory/distiller"; const { workflow, generatorAgentId } = createResidentDistiller({ + mailTo: "resident-distiller@tenant.example.com", inference: { sources: [{ provider: "openai", model: "gpt-4.1-mini" }], }, @@ -83,6 +84,9 @@ const { workflow, generatorAgentId } = createResidentDistiller({ // Deploy only if you need a multi-writer pull consumer — not default ingest. ``` +The run fires on mail to `mailTo`. The host decides when: mail that address +on a schedule, e.g. from `@corbits/cron`. This package owns no clock. + ## Substrate (plane) | Piece | Where |