feat(registration): self-register FuzeAgent with the FuzeFront portal - #140
Merged
Conversation
FuzeAgent's portal presence is currently a HARDCODED entry in FuzeFront's
backend/applications/src/app-registry/builtins.ts — FuzeFront's source has to change
for FuzeAgent's own menu entry to change. This moves that declaration here.
- registration/manifest.json — identity + `nav: { section: "build", order: 10 }`,
leading the build stage. Menu order was previously unexpressible: the registry
sorted by created_at, so the side menu was in registration order.
integration.type is genuinely `module-federation` here, unlike most siblings. The
contract is copied from services/ui-react/vite.config.ts and verified to match:
scope=fuzeagentApp, module=./FuzeAgentApp, remoteEntry at the prod host.
- registration/policy.json — derived from services/orchestrator/models.py:
Organization, Team, Agent, Task, plus Goal (the organizational-goal surface the MCP
server exposes). Agent:deploy and Task:assign are split from ordinary writes because
they cause an autonomous agent to actually RUN — a different kind of authority from
editing a record.
- .fuze/manifest.json:
* mcp block with enabled:TRUE — this is not a scaffold. mcp-servers/fuzeagent-server/
already serves 15+ tools against the hierarchy API. The note names the tools that
MUST be classified mutates:true (assign_task, deploy_agent, create_custom_agent,
update_task_status, create_organizational_goal, update_goal_progress,
create_goal_conversation) and flags the missing tools.json for mcp-maintainer.
* a2a block naming the REAL serving role `agent-orchestrator` — agent-templates/a2a/
implements card_generator/adapter/authz/identity and the role is fully described.
Left enabled:false because flipping it requires verifying the card projects
schema-valid, which is a2a-maintainer's call, not a manifest edit's.
Validated: manifest passes the generated AppManifest schema; the MF scope/module match
vite.config.ts exactly; every permission resolves to a resource+action the same
document declares.
NOT DONE, deliberately: the init container is not wired. deploy/helm/fuzeagent exists
but this is a multi-service deployment and exactly one deployment must register —
wiring more than one would have them race and duplicate-register. Picking the owner is
devops-engineer's call, flagged not guessed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GaPa3JgrVNtWrGvqQEAEqv
…rmissions Two red checks with the same root shape: something was DECLARED without the file that backs it, and neither gate could self-heal. governance-sync: the manifest declares `mcp-maintainer`, and FuzeSDLC now carries the canonical agent — but governance_sync.py only COPIES a file that already exists and has drifted. A wholly absent one is reported `missing` and hard-fails (governance_sync.py:84), so `--write` was never going to create it. Added .claude/agents/mcp-maintainer.md from the canonical, plus the mcp-maintain.yml workflow where absent, so the declared surface actually has something behind it. auto-merge.yml: no permissions block, so the default read-only GITHUB_TOKEN made `gh pr merge --auto` fail with "Resource not accessible by integration" every run. FuzeSDLC#66 fixed the canonical template; this copy was stale. Workflow drift is deliberately ADVISORY in governance-sync (the job cannot push workflow files), so nothing would ever have reconciled it on its own. Verified with governance_sync.py against the canonical: ok=True, missing=[]. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GaPa3JgrVNtWrGvqQEAEqv
No repo in the family declared `mobile` at all, so `mobile-app-engineer` had nothing to read on merge and no gate could tell "mobile is out of scope" from "nobody wrote it down". Uses the EXISTING canonical contract — FuzeSDLC agent-templates/schema/mobile-requirements.schema.json — which already sanctions a `mobile` block inside .fuze/manifest.json. No new schema and no new agent were invented: mobile-app-engineer, mobile-packaging and mobile-conformance already exist. strategy: pwa matches what FuzeFront actually ships — an installable PWA wrapped as a signed Android TWA — rather than react-native/flutter, which nothing here uses. targets omit ios until there is a signing identity for it. The acceptance list is deliberately concrete (no horizontal scroll at 375, 44px tap targets, Lighthouse >= 80, and the standalone URL rendering with no portal chrome), because an acceptance block of good intentions verifies nothing. Validated against the canonical schema; confirmed a missing `required`, an unknown strategy and an unknown target are all rejected. NOTE ON SEQUENCING: this declares mobile INTENT only. The `modes: ["portal", "standalone"]` + `routing.host` that a mobile build actually wraps cannot be added to registration/manifest.json until FuzeFront#444 merges — AppManifest is additionalProperties:false, so those keys would fail validation against the currently published schema. Registration side follows once that lands. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GaPa3JgrVNtWrGvqQEAEqv
This repo declares a `mobile` block, and a mobile build can only wrap a URL that stands on its own — an app store has nothing to point at otherwise. The manifest previously said only `mode: "portal"`, so there was no standalone surface to wrap and no host to wrap it at. That made the mobile contract unsatisfiable on its face. FuzeFront#444 added `modes` to AppManifest for exactly this: the scalar `mode` is single-valued and so cannot express a product that is genuinely both — mounted in the host shell on the web, and separately reachable on its own host for the mobile wrapper. `modes` is the multi-valued form and wins where both are present. - `modes: ["portal", "standalone"]` — portal stays the default surface. The scalar `mode` is kept unchanged (still REQUIRED, now deprecated) and equals `modes[0]`, as the contract requires. - `routing.host` — the user-facing standalone host, `<slug>.fuzefront.com`. Distinct from `*.prod.fuzefront.com`, which is the infra host serving the portal `remoteEntry`. Portal integration is untouched. Validated against packages/onboarding-kit/manifest.schema.json at merged master (9d2b0af). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GaPa3JgrVNtWrGvqQEAEqv
|
|
||
| - name: Checkout PR head (writable, same-repo only) | ||
| if: steps.guard.outputs.ok == 'true' | ||
| uses: actions/checkout@v4 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
FuzeAgent's portal presence is currently a hardcoded entry in FuzeFront's
builtins.ts— FuzeFront's source has to change for FuzeAgent's own menu entry to change. This moves that declaration into this repo, where it belongs.Platform side: FuzeFront#426 (merged).
Module Federation is real here
Unlike most siblings (which register as
iframebecause they expose noremoteEntry),integration.typeis genuinelymodule-federation. The contract is copied fromservices/ui-react/vite.config.tsand verified to match:scopefuzeagentAppnamemodule./FuzeAgentAppexposeskeyremoteEntryhttps://fuzeagent.prod.fuzefront.com/remoteEntry.jsfilename+ hostMenu placement
FuzeAgent leads the build stage. Menu order was previously unexpressible: the registry sorted by
created_at, so the side menu was in registration order.Policy
Derived from
services/orchestrator/models.py—Organization,Team,Agent,Task, plusGoal(the organizational-goal surface the MCP server exposes).Agent:deployandTask:assignare separated from ordinary writes deliberately: they cause an autonomous agent to actually run, which is a different kind of authority from editing a record.MCP is declared
enabled: true— because it's already realmcp-servers/fuzeagent-server/already serves 15+ tools against the hierarchy API. This is the only repo in the rollout where the MCP block isn't a scaffold.Outstanding, and flagged rather than invented: there's no
tools.jsondeclaringmutatesper tool. These mutate and must bemutates: true:assign_task·deploy_agent·create_custom_agent·update_task_status·create_organizational_goal·update_goal_progress·create_goal_conversationThe
list_*/get_*tools aremutates: false.deploy_agentdeserves particular care — it starts an autonomous agent, so it must never be reachable as a side effect of a read. Classification ismcp-maintainer's to reconcile.A2A block names the real serving role
agent-templates/a2a/implements card generation, adapter, authz and identity, andagent-templates/roles/agent-orchestrator/role.jsonis a fully-described serving role. The manifest namesagent-orchestratoraccurately — my first draft had guessedagent-platform, which would have been wrong.Left
enabled: falseon purpose: flipping it requires verifying the card projects schema-valid against the frozen contract —a2a-maintainer's call, not something a manifest edit should assert.🚨 NOT DONE — init container not wired
deploy/helm/fuzeagent/exists, but this is a multi-service deployment and exactly one deployment must run registration. Wiring more than one would have them race and duplicate-register on every rollout. Choosing the owner isdevops-engineer's call, flagged rather than guessed — steps are inregistration/README.md.Follow-up
Once this is live, the hardcoded
fuzeagententry in FuzeFront'sbuiltins.tscan be retired — deliberately last, and behind a flag, so the app never vanishes from the menu in the gap.Notes
open-draft-prworkflow; marked ready for review, since per CLAUDE.md agent PRs are non-draft +auto-mergeand drafts are only legitimate when labelledwip/hold/blocked.Auto Merge PRwill fail until FuzeSDLC#66 lands — the canonicalauto-merge.ymltemplate has nopermissionsblock, sogh pr merge --autohitsResource not accessible by integrationin every consuming repo.