New circuitforge_core.task_bridge module: ExternalTask (frozen dataclass, schema v1) plus push_tasks() httpx wrapper. Pilot consumer is Kiwi, pushing pantry expiry alerts into Focus Flow (AGPL-3.0, external project). The contract lives in cf-core (MIT) so AGPL and BSL code never share a process or artifact — each product implements its own exporter/receiver. No transport server, no auth/token generation, no product-specific behavior — pure data contract + reusable push helper, same spirit as the existing sync and tasks modules. Bump to 0.22.0. Closes: #66
2.5 KiB
task_bridge
Shared MIT data contract for pushing tasks from a CF product into an external scheduler. Pilot consumer: Kiwi's pantry expiry alerts pushed into Focus Flow, Ashley Venn's ADHD-first scheduler (AGPL-3.0, external project).
Why this lives in cf-core
Focus Flow is AGPL-3.0; CF's AI features are BSL 1.1. To avoid any question of AGPL reach extending into CF's licensed code, the two sides never share a process or artifact:
- The data contract (this module) is MIT, a pure data definition with no product-specific logic.
- Each product's exporter/receiver lives in that product's own repo, under its own licensing.
- The two sides talk only over local HTTP, never a shared library or process.
Design spec: circuitforge-plans/shared/superpowers/specs/2026-07-05-focus-flow-task-bridge-design.md.
Usage
from circuitforge_core.task_bridge import ExternalTask, push_tasks
task = ExternalTask(
source_product="kiwi",
external_id="kiwi:item:1234", # stable, idempotent per source item — upserts, not duplicates
title="Use up milk",
due_at="2026-07-07T00:00:00Z", # ISO 8601 UTC
notes="Opened 2026-07-01",
)
push_tasks("http://127.0.0.1:8512/import/tasks", token, [task])
kind is always "flexible" in schema v1 — Focus Flow's calm task kind. External sources can never set "inflexible", "critical", "locked", or "surprise", so no CF product can inject urgency into another product's UX.
status is "active" (default) or "cancelled" — push a "cancelled" record when the source item is deleted or edited away before the external scheduler marks it complete.
API
ExternalTask(source_product, external_id, title, due_at, notes=None, kind="flexible", status="active")— frozen dataclass; validates required fields andkind/statusin__post_init__..to_dict()serializes to the wire format.push_tasks(endpoint, token, tasks, *, timeout=10.0)— POSTs{"tasks": [...]}withAuthorization: Bearer <token>. RaisesTaskBridgeErroron transport failure or non-2xx response.
What this module does not do
No transport server, no auth/token generation or pairing logic, no product-specific behavior (diffing, callback handling, inventory updates). Those live entirely on the consuming product's side — see Kiwi's focus_flow service for the reference implementation.
Install: pip install circuitforge-core[task-bridge] (pulls in httpx).