Commit Graph

267 Commits

Author SHA1 Message Date
Hongming Wang
25bbfd3bfc fix(security): C2 from #169 — reject spoofed source_id in activity.Report
Cherry-picks the one genuinely new fix from #169 after confirming the
rest of that PR is already covered on main (C1/C3/C5 by wsAuth group,
C6 by #94+#119 SSRF blocklist, C4 ownership by existing WHERE filter).

Pre-existing middleware (WorkspaceAuth on /workspaces/:id/* sub-routes)
proves the caller owns the :id path param. But the body field
source_id was never validated — a workspace authenticated for its own
/activity endpoint could still attribute logs to a different workspace
by setting source_id=<foreign UUID>. Rejected with 403 now.

No schema change, no new middleware. 4-line handler delta. Closes the
only real gap in #169; #169 itself will be closed as superseded.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 11:15:08 -07:00
Hongming Wang
2a0552214a Merge pull request #207 from Molecule-AI/fix/issue-115-scheduler-busy-skip
fix(scheduler): #115 — skip cron fire when workspace busy
2026-04-15 11:13:20 -07:00
Hongming Wang
fb942fbb0c fix(scheduler): #115 — skip cron fire when workspace is busy
Closes #115. The Security Auditor hourly cron (and likely others) hit a
~36% miss rate because the platform's A2A proxy rejected fires with
"workspace agent busy — retry after a short backoff" while the agent was
still executing the prior audit. That error was recorded as a hard
failure and polluted last_error.

New behaviour:

Before fireSchedule calls into the A2A proxy, it reads
workspaces.active_tasks for the target. If >0, it:
  - Advances next_run_at to the next cron slot (cron keeps ticking)
  - Bumps run_count
  - Sets last_status='skipped' + last_error=<reason>
  - Inserts a cron_run activity_logs row with status='skipped' + error_detail
  - Broadcasts CRON_SKIPPED for canvas + operators

Effect: busy-collision ceases to be an error. The history surface now
distinguishes "ran and failed" from "skipped because busy". Operators
can tell the difference at a glance, and the liveness view doesn't
stall waiting for the next ticker cycle.

Pairs with #149 (dedicated heartbeat pulse) and #152 problem B
(error_detail surfaced in history) for a coherent scheduler story.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 11:13:15 -07:00
Hongming Wang
187e8c30ed Merge pull request #206 from Molecule-AI/fix/issue-152-schedule-history-error-detail
fix(scheduler): #152 problem B — surface cron error_detail in schedule history
2026-04-15 11:11:21 -07:00
Hongming Wang
ce88a396da fix(scheduler): #152 problem B — persist and surface cron error_detail
Closes #152 problem B (schedule history API drops error detail).

Two tiny changes:

1. scheduler.fireSchedule now writes lastError into activity_logs.error_detail
   when inserting the cron_run row. Previously the column was left NULL even
   on failure because the INSERT didn't include it.

2. schedules.History SELECT now reads error_detail and includes it in the
   JSON response under error_detail. Frontend + audit cron can now display
   "why did this run fail" instead of just "status=error".

No schema change — activity_logs.error_detail already exists from
migration 009. This just starts using the column.

Problem A of #152 (Research Lead ecosystem-watch 50% error rate on its
own) is a separate ops investigation and stays open.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 11:11:16 -07:00
Hongming Wang
ddce151698 Merge pull request #203 from Molecule-AI/fix/issue-168-route-split
fix(auth): #168 — CanvasOrBearer on PUT /canvas/viewport (route-split)
2026-04-15 11:09:22 -07:00
Hongming Wang
7a16eb4f70 fix(auth): #168 — CanvasOrBearer middleware for PUT /canvas/viewport only
Closes #168 by the route-split path from #194's review. #167 put PUT
/canvas/viewport behind strict AdminAuth, breaking canvas drag/zoom
persist because the canvas uses session cookies not bearer tokens.

New narrow middleware CanvasOrBearer:
  - Accepts a valid bearer (same contract as AdminAuth) OR
  - Accepts a request whose Origin exactly matches CORS_ORIGINS
  - Lazy-bootstrap fail-open preserved for fresh installs

Applied ONLY to PUT /canvas/viewport. The softer check is acceptable
there because viewport corruption is cosmetic-only — worst case a
user refreshes the page. This middleware must NOT be used on routes
that leak prompts (#165), create resources (#164), or write files
(#190) — see #194 review for why.

The other canvas-facing routes mentioned in #168 (Events tab, Bundle
Export/Import) remain behind strict AdminAuth pending a proper
session-cookie-accepting AdminAuth (#168 follow-up for Phase H).

6 new tests cover: bootstrap fail-open, no-creds 401, canvas origin
match, wrong origin 401, empty origin rejected, localhost default.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 11:09:16 -07:00
Hongming Wang
87d330cf15 Merge pull request #198 from Molecule-AI/fix/a2a-compat-batch-173-174-175
fix(a2a): A2A protocol compliance — cancel(), capabilities, push store (closes #173 #174 #175)
2026-04-15 11:02:11 -07:00
Hongming Wang
1634594ca0 Merge branch 'main' into fix/a2a-compat-batch-173-174-175 2026-04-15 11:01:54 -07:00
Hongming Wang
adbcb4fe3b Merge pull request #200 from Molecule-AI/fix/issue-190-templates-import-auth
fix(security): #190 — gate POST /templates/import behind AdminAuth
2026-04-15 11:00:54 -07:00
Hongming Wang
7a164f98d3 fix(security): #190 — gate POST /templates/import behind AdminAuth
Closes #190 (HIGH). The route was registered on the root router with no
auth middleware, letting any unauthenticated caller write arbitrary files
into configsDir via a crafted template. Same vulnerability class as #164
(bundles/import) and path-traversal risk same as #103 (org/import).

One-line gate via the existing wsAdmin pattern. Lazy-bootstrap fail-open
preserved for fresh installs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 11:00:49 -07:00
Hongming Wang
fb8ba8e3d3 Merge pull request #197 from Molecule-AI/fix/ci-python-bypass-setup-python
fix(ci): apply bypass-setup-python to main (missed in #186 squash)
2026-04-15 10:58:27 -07:00
Hongming Wang
dde97433ed fix(ci): apply user's bypass-setup-python to main (missed in #186 squash-merge)
#186's squash-merge commit (3ff40c4b) took 15e15a21 (AGENT_TOOLSDIRECTORY
override) but missed a6cfc5f (bypass setup-python entirely) which was
pushed to the PR branch after the merge was initiated. The merge
commit still has the old setup-python@v5 job config.

Applies a6cfc5f's ci.yml verbatim via git checkout. Restores the
Homebrew-python3.11 bypass path that the user prototyped. No other
changes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 10:58:22 -07:00
Backend Engineer
4cea1c6478 fix(a2a): cancel() event, stateTransitionHistory capability, wire push store (#173 #174 #175)
#173 — implement cancel() in LangGraphA2AExecutor: emits
TaskStatusUpdateEvent(state=canceled, final=True) so clients see the
state transition rather than silence. Removes pragma: no cover.
Test: test_cancel_emits_canceled_event.

#174 — add stateTransitionHistory=True to AgentCapabilities in main.py
so microsoft/agent-framework clients know they can request full task
history via the A2A protocol.

#175 — wire InMemoryPushNotificationConfigStore and PushNotificationSender
into DefaultRequestHandler so the advertised pushNotifications capability
is backed by a real store. Both classes live in a2a.server.tasks (a2a-sdk
0.3.25); import confirmed by probe.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 17:58:10 +00:00
Hongming Wang
53299828a4 Merge pull request #187 from Molecule-AI/fix/issue-179-trusted-proxies
fix(router): SetTrustedProxies(nil) closes rate-limit bypass via X-Forwarded-For (#179)
2026-04-15 10:55:01 -07:00
Hongming Wang
5f56e6d555 Merge pull request #192 from Molecule-AI/fix/issue-170-secret-delete-auth
fix: require workspace auth on DELETE /secrets/:key (#170)
2026-04-15 10:54:58 -07:00
Hongming Wang
f2b34e590b Merge pull request #189 from Molecule-AI/fix/issue-178-security-auditor-cron
fix(template): revert Security Auditor cron to 2x/day (closes #178)
2026-04-15 10:54:55 -07:00
Hongming Wang
8e93c4ea73 Merge branch 'main' into fix/issue-178-security-auditor-cron 2026-04-15 10:54:45 -07:00
Hongming Wang
96e8cfbd4c Merge branch 'main' into fix/issue-170-secret-delete-auth 2026-04-15 10:54:36 -07:00
Hongming Wang
271e3427c4 Merge branch 'main' into fix/issue-179-trusted-proxies 2026-04-15 10:54:21 -07:00
Hongming Wang
3ff40c4b68 chore(ci): migrate all jobs to self-hosted macOS arm64 runner
* chore(ci): migrate all jobs to self-hosted macOS arm64 runner

Switches every job in `ci.yml` and `publish-platform-image.yml` from
`ubuntu-latest` to `[self-hosted, macos, arm64]` to avoid GitHub-hosted
minute rate limits. All jobs run on a single Apple-silicon self-hosted
runner registered at the Molecule-AI org level.

Notable non-trivial adaptations (macOS runners can't use `services:` and
some GHA marketplace actions are Linux-only):

- e2e-api: `services: postgres/redis` replaced with inline `docker run`
  steps. Ports remapped to 15432/16379 to avoid collision with anything
  the host may already expose on the standard ports. Containers are named
  (`molecule-ci-postgres` / `molecule-ci-redis`) and torn down in an
  `if: always()` step. Postgres readiness is still gated on pg_isready
  via `docker exec`.
- shellcheck: `ludeeus/action-shellcheck` is a Docker action, Linux-only.
  Replaced with a direct `shellcheck` invocation (pre-installed on the
  runner) that scans `tests/e2e/*.sh` with `--severity=warning`.
- publish-platform-image: added `docker/setup-qemu-action@v3` and an
  explicit `platforms: linux/amd64` on both `docker/build-push-action`
  invocations. The runner is arm64 but Fly tenant machines pull amd64,
  so QEMU-emulated cross-arch builds are required. GHA cache-from/cache-to
  behavior is unchanged.

Runner prereqs (one-time host setup):
- Docker Desktop installed and running (for e2e-api + image publish)
- `shellcheck` on PATH
- `docker` on PATH
- Go / Node / gh / Python are installed via setup-* actions per job

* fix(ci): set AGENT_TOOLSDIRECTORY for python-lint on self-hosted runner

setup-python@v5 defaults to /Users/runner/hostedtoolcache which doesn't
exist on the hongming-claw self-hosted runner. AGENT_TOOLSDIRECTORY tells
the action to use a writable path under the runner user's home directory.

Fixes the only failing job in CI run 24469156329 on PR #186.

---------

Co-authored-by: Hongming Wang <HongmingWang-Rabbit@users.noreply.github.com>
2026-04-15 10:48:27 -07:00
Backend Engineer
734c0f6bcf fix: require workspace auth on DELETE /secrets/:key (#170)
The route wsAuth.DELETE("/secrets/:key", sech.Delete) was already moved
inside the WorkspaceAuth group in a prior commit, closing the CWE-306
unauthenticated-delete vector. This commit adds two regression tests to
lock that in:

- TestWorkspaceAuth_Issue170_SecretDelete_NoBearer_Returns401: workspace
  with live tokens, no bearer header → 401 (blocks the attack).
- TestWorkspaceAuth_Issue170_SecretDelete_FailOpen_NoTokens: workspace
  with no tokens (bootstrap/legacy) → 200 (fail-open preserved).

Mirrors the TestAdminAuth_Issue120_* and TestWorkspaceAuth_C4_C8_* patterns.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 17:42:08 +00:00
Hongming Wang
7b0387e9be fix(template): revert Security Auditor cron to 2x/day — closes #178
Every-10-min cadence introduced in PR #159 increased Security Auditor
from 2 runs/day to 144 runs/day (144x). Combined with PM, Research Lead,
Dev Lead, and other hourly evolution-lever crons, this is the likely
root cause of the P0 OAuth quota exhaustion (#160, resets Apr 17 23:00 UTC).

Restored: cron_expr 7 6,18 * * * (twice daily, 12-hour interval)
Schedule name updated to match new cadence.
Audit prompt content (DAST teardown, PM routing, PM deliverable) retained.
2026-04-15 17:33:54 +00:00
Hongming Wang
6582ece523 Merge pull request #188 from Molecule-AI/fix/e2e-auth-headers-post-167
fix(tests): e2e auth headers for /events + /bundles/export (post #167)
2026-04-15 10:33:44 -07:00
Hongming Wang
8f23908304 fix(tests): add auth headers to e2e GET /events + /bundles/export (post #167)
PR #167 gated /events and /bundles/export/:id behind AdminAuth. The e2e
script's 3 calls to these routes were unauthenticated and broke when the
runner picked them up for the first time on PR #186 (self-hosted runner
migration). Same admin-gate contract, same fix pattern as the #99/#110
e2e hotfixes.

POST /bundles/import is left unauthenticated because by that point in
the script both workspaces have been deleted and #110 revoked their
tokens, so HasAnyLiveTokenGlobal=0 and AdminAuth fails-open.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 10:33:38 -07:00
Backend Engineer
06e02a310c fix(router): call SetTrustedProxies(nil) to close IP-spoofing bypass (#179)
Without this call Gin's default trusts all X-Forwarded-For headers, letting
any caller rotate their effective IP and bypass per-IP rate limiting.
SetTrustedProxies(nil) forces c.ClientIP() to always return the real
TCP RemoteAddr.

Adds two regression tests: one documenting the pre-fix bypass, one
asserting the spoofed header is ignored after the fix.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 17:32:54 +00:00
Hongming Wang
9979845391 Merge pull request #182 from Molecule-AI/fix/issue-177-documentation-specialist-dir
fix(template): add missing documentation-specialist/system-prompt.md (closes #177)
2026-04-15 10:31:02 -07:00
Hongming Wang
4bd377fe28 Merge branch 'main' into fix/issue-177-documentation-specialist-dir 2026-04-15 10:30:49 -07:00
Hongming Wang
762b2f14a2 Merge pull request #185 from Molecule-AI/fix/issue-180-approvals-auth
fix(security): gate GET /approvals/pending behind AdminAuth (#180)
2026-04-15 10:30:38 -07:00
Backend Engineer
9122d6aeea fix(security): gate GET /approvals/pending behind AdminAuth (#180)
GET /approvals/pending was registered on the open router with no
middleware, allowing any unauthenticated caller to enumerate all pending
approvals across every workspace on the platform.

Fix: add inline middleware.AdminAuth(db.DB) to the route registration,
matching the pattern used in PR #167 for bundles, events, and viewport.

The three workspace-scoped approvals routes (POST/GET /approvals,
POST /approvals/:id/decide) were already correctly behind WorkspaceAuth
inside the wsAuth group — no change needed there.

Tests: two new regression tests in wsauth_middleware_test.go —
  TestAdminAuth_Issue180_ApprovalsListing_NoBearer_Returns401
  TestAdminAuth_Issue180_ApprovalsListing_FailOpen_NoTokens

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 17:25:09 +00:00
Hongming Wang
b2d7c3407f fix(template): add missing documentation-specialist/system-prompt.md (closes #177) 2026-04-15 17:23:38 +00:00
Hongming Wang
aded2e3762 Merge pull request #159 from Molecule-AI/chore/orchestrator-worker-split
chore(template): orchestrator/worker split — leaders pulse every 5min, workers stay reactive (supersedes #158)
2026-04-15 09:53:51 -07:00
Hongming Wang
26d620957d Merge pull request #167 from Molecule-AI/fix/issues-164-165-166-auth-gaps
fix(security): #164 #165 #166 — gate 6 unauth routes behind AdminAuth
2026-04-15 09:52:38 -07:00
Hongming Wang
186206b33f fix(security): #164 + #165 + #166 — gate 6 unauth routes behind AdminAuth
CRITICAL (#164):
  POST /bundles/import — anon callers could create arbitrary workspaces
  with user-supplied system prompts, plugins, and secrets envelopes.
  Fixed by gating behind AdminAuth (bundleAdmin group).

HIGH (#165):
  GET /bundles/export/:id — anon UUID probe leaked full system prompts,
  agent_card, plugins, memory for any workspace.
  GET /events + GET /events/:workspaceId — anon read of the append-only
  event log leaked org topology, workspace names, card fragments.
  Both moved into the same bundleAdmin / eventsAdmin groups.

MEDIUM (#166):
  PUT /canvas/viewport — anon callers could reset shared viewport state.
  Gated via a scoped viewportAdmin group; GET stays open so canvas
  bootstraps without a bearer.
  GET /admin/liveness — operational-intel leak (scheduler cadence
  reveals work pattern). Inline AdminAuth on the single handler.

All 6 routes use the same lazy-bootstrap admin auth the rest of the
platform uses: zero-token installs fail-open, once any token exists
every request must present a valid bearer.

Known follow-up: canvas uses session cookies not bearer tokens (same
pattern as #138). In multi-tenant production these canvas features —
Events tab, Export/Duplicate, viewport persist — will return 401 once
a workspace is token-enrolled. Needs cookie-accepting AdminAuth as a
follow-up (tracked as option B in #138 triage discussion); a new issue
will be filed for that scope. The security gain from closing #164
CRITICAL outweighs the canvas UX regression for tonight.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 09:52:32 -07:00
Hongming Wang
175bc2de50 Merge pull request #162 from Molecule-AI/fix/issue-138-field-whitelist
fix(auth): #138 — field-level authz on PATCH /workspaces/:id (canvas regression fix)
2026-04-15 09:39:22 -07:00
Hongming Wang
cbf46a837b fix(auth): #138 — field-level authz on PATCH /workspaces/:id
Closes #138. #125 moved PATCH /workspaces/:id into the wsAdmin AdminAuth
group to close the #120 unauth vulnerability, but broke canvas drag-
reposition and inline rename because canvas uses session cookies not
bearer tokens. Multi-tenant deployments with any live token would have
seen every canvas PATCH 401.

Option A per #138 triage: PATCH goes back on the open router, but
WorkspaceHandler.Update now enforces field-level authz:

  Cosmetic (no bearer required):
    name, role, x, y, canvas

  Sensitive (bearer required when any live token exists):
    tier          — resource escalation
    parent_id     — A2A hierarchy manipulation
    runtime       — container image swap
    workspace_dir — host bind-mount redirection

Fail-open bootstrap: HasAnyLiveTokenGlobal = 0 → pass-through
(fresh install, pre-Phase-30 upgrade path). Matches the same
lazy-bootstrap contract WorkspaceAuth and AdminAuth use elsewhere.

3 new tests cover all three branches of the matrix (cosmetic
no-bearer, sensitive no-bearer-rejected, sensitive fail-open).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 09:39:09 -07:00
Hongming Wang
06fed1776a Merge pull request #119 from Molecule-AI/fix/111-112-clean
fix(security+scheduler): IPv6 SSRF gap + scheduler unit tests [supersedes #111, #112]
2026-04-15 09:36:59 -07:00
Hongming Wang
40aceb03e3 Merge pull request #110 from Molecule-AI/fix/delete-revokes-tokens
fix(security): revoke workspace auth tokens on workspace delete
2026-04-15 09:36:21 -07:00
Hongming Wang
0003f7970a Merge branch 'main' into fix/111-112-clean 2026-04-15 09:36:14 -07:00
Hongming Wang
34beac349e Merge branch 'main' into fix/delete-revokes-tokens 2026-04-15 09:35:44 -07:00
Hongming Wang
c59b39ed5b Merge pull request #161 from Molecule-AI/fix/broken-update-tests-post-125
fix(tests): add EXISTS probe mock to 4 WorkspaceUpdate tests (post #125)
2026-04-15 09:35:18 -07:00
Hongming Wang
ba7064f75c fix(tests): add EXISTS probe mock to 4 WorkspaceUpdate tests
#125 added a SELECT EXISTS guard before WorkspaceHandler.Update applies
any UPDATE so nonexistent workspace IDs return 404 instead of silent
zero-row successes. The 4 existing WorkspaceUpdate_* sqlmock tests
didn't mock the probe, so they broke on main. This was not caught
because CI is blocked by the Actions billing cap.

Adds ExpectQuery for the EXISTS probe to:
- TestWorkspaceUpdate_ParentID
- TestWorkspaceUpdate_NameOnly
- TestWorkspaceUpdate_MultipleFields
- TestWorkspaceUpdate_RuntimeField

TestWorkspaceUpdate_BadJSON doesn't need the fix — it aborts on
c.ShouldBindJSON before reaching the guard.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 09:35:08 -07:00
rabbitblood
9fd4f8a275 chore(template): orchestrator/worker split — leaders poll every 5min, workers stay reactive
Supersedes #158 (10-min uniform bump). That PR was too blunt — it treated
research/audit/orchestration crons the same when they have fundamentally
different cost/value/cadence profiles.

## The split

Three layers, three cadences, grounded in the survey of Hermes/Letta/
Trigger.dev/Inngest/AG2/Rivet/n8n/Composio/SWE-agent done this session.
Nobody in that survey runs while(true) per agent — they all combine
event-driven reactivity with short orchestration pulses on a coordinator.
This PR implements that split for our 12-workspace template.

| Layer | Roles | Cadence | Purpose |
|---|---|---|---|
| Orchestration | PM, Dev Lead, Research Lead | every 5 min | Check backlog, dispatch work, review completed tasks |
| Audit | Security Auditor | every 10 min | Focused security audit |
| Audit | UI/UX Designer | every 15 min | Vision-heavy, dial back from 10 |
| Deep-work | Research Lead (eco-watch) | every 30 min (8,38) | Was hourly |
| Deep-work | Dev Lead (template fitness) | every 30 min (15,45) | Was hourly |
| Deep-work | Technical Researcher (plugins) | hourly (unchanged) | Research-heavy, slow |
| Deep-work | DevOps (channels) | hourly (unchanged) | Research-heavy, slow |
| Reactive | BE, FE, DevOps, Docs | no cron | Execute A2A delegations |

## Orchestration pulse prompts

The three new schedules each carry a detailed orchestration_prompt:

- **PM** (5-min): scan all 12 workspaces, scan GH PRs/issues backlog
  (external), scan memory backlog (internal), dispatch up to 3 tasks per
  pulse, review completed work, write pulse summary to memory. Hard
  rules: under 90s wall-clock, never dispatch to busy agents, write
  "orchestrator-clean" and stop if genuinely nothing to do.

- **Dev Lead** (5-min, offset +1 from PM): same shape, scoped to
  engineering team. Reviews open PRs from direct reports, matches idle
  engineers to labeled GH issues (security/bug/feature), dispatches with
  "fix/issue-N-slug" branch convention. Skips pulse if own template
  fitness audit is in flight (:15, :45).

- **Research Lead** (5-min, offset +2 from PM): same shape, scoped to
  research team. Matches Market Analyst / Technical Researcher /
  Competitive Intelligence to research-labeled issues or memory-stashed
  questions. Max 2 A2A per pulse (research is slow). Skips pulse if own
  eco-watch is in flight (:8, :38).

## Cadence offset table

No two crons fire in the same minute:

  :01,:11,:21,:31,:41,:51 — Security audit (Security Auditor)
  :02,:07,:12,:17,:22,:27,:32,:37,:42,:47,:52,:57 — Dev Lead orchestrator
  :04,:09,:14,:19,:24,:29,:34,:39,:44,:49,:54,:59 — Research Lead orchestrator
  :01,:06,:11,:16,:21,:26,:31,:36,:41,:46,:51,:56 — PM orchestrator
  :05,:20,:35,:50 — UI/UX audit (UIUX Designer)
  :08,:38 — Ecosystem watch deep-work (Research Lead)
  :15,:45 — Template fitness deep-work (Dev Lead)
  :22 — Plugin curation (Technical Researcher)
  :47 — Channel expansion (DevOps Engineer)

Note PM and Security Auditor share :01 — this is fine because they
target different workspaces so scheduler concurrency handles it.

## Cost estimate

- PM pulse: 12/hour × 24 × ~3k tokens = 864k tokens/day/org ~ $5/day
- Dev Lead pulse: same ~ $5/day
- Research Lead pulse: same ~ $5/day
- Audits (security 10min, UIUX 15min): ~$8/day/org combined
- Deep-work crons (unchanged from original): ~$4/day/org

**Total ~$27/day/org**. Comparable to #158's $25 but MUCH higher
utility because orchestration produces dispatches that keep workers
busy, whereas #158 just fired more audits against the same team.

Closes #158 (superseded — will close that PR with a pointer to this one).

## Related research
See docs/ecosystem-watch.md `### Hermes Agent` and today's research agent
output: event-driven + reflection-on-completion + short orchestration
pulses on leaders is the shape that delivers 24/7 activity without
runaway cost. This is the concrete implementation.
2026-04-15 09:05:08 -07:00
Hongming Wang
330867d24b Merge pull request #157 from Molecule-AI/chore/eco-watch-2026-04-15-pm
chore(eco-watch): 2026-04-15 PM survey — Microsoft Agent Framework, Vercel Open Agents
2026-04-15 04:20:25 -07:00
Research Lead
f7b24a1120 chore(eco-watch): 2026-04-15 PM survey — Microsoft Agent Framework, Vercel Open Agents
Two new entries added from the second daily pass (first run merged as PR #150
at 03:20 UTC). Both surfaced in the afternoon trending windows and were not
covered by the morning run.

- microsoft/agent-framework (~9.5k ): official Microsoft successor to
  AutoGen; ships migration guide and April 2026 .NET release. Directly affects
  our autogen adapter in workspace-template/adapters/. Filed issue #156 to
  evaluate adapter update.

- vercel-labs/open-agents (~2.2k , +1,020 today): cloud coding agent template
  from Vercel Labs (same team as Skills CLI). Notable for agent-outside-sandbox
  architecture and snapshot-based VM resumption — a more efficient approach
  than our current Docker restart + git-clone pattern.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 11:12:49 +00:00
Hongming Wang
718c05d847 Merge pull request #155 from Molecule-AI/fix/issue-151-register-security-headers
fix(security): #151 — register SecurityHeaders middleware
2026-04-15 03:51:02 -07:00
Hongming Wang
4b6482bea0 fix(security): #151 — register SecurityHeaders middleware
Closes #151. The middleware was already implemented + tested (3 passing
tests in securityheaders_test.go covering base set, multi-route, and
the don't-override-existing contract) but never registered in router.go.

One-line wire-up, runs after TenantGuard so rejected requests still
get the same headers as accepted ones, and before routes so handlers
can still opt out by setting their own header before c.Next() returns.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 03:50:52 -07:00
Hongming Wang
00126db676 Merge pull request #150 from Molecule-AI/chore/eco-watch-2026-04-15
chore(eco-watch): 2026-04-15 daily survey — Skills CLI, Archon, Claude Code Routines
2026-04-15 03:20:58 -07:00
Hongming Wang
a95fbf7f52 Merge pull request #149 from Molecule-AI/fix/140-scheduler-heartbeat-pulse
fix(scheduler): independent heartbeat pulse so liveness doesn't false-stale during long fires (#140)
2026-04-15 03:20:55 -07:00
Research Lead
f922f87a22 chore(eco-watch): 2026-04-15 daily survey — 3 new entries, 3 issues
New entries:
- vercel-labs/skills: canonical agentskills.io CLI (14.2k , +153)
- coleam00/Archon: YAML-DAG harness builder for AI coding (18.1k , +396)
- Claude Code Routines: Anthropic cloud-scheduled agents (611 HN pts)

Issues filed:
- #146 plugins/: align with agentskills.io SKILL.md spec
- #147 workspace_schedules: add GitHub event trigger types
- #148 workspace-template/: workflow.yaml YAML-DAG convention

HEAD at survey time: 229c2ab

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 10:14:59 +00:00