feat(config): per-repo Penpot team mapping (pin designer to a specific team, not list-and-guess) #255
Labels
No labels
area:agents
area:dashboard
area:database
area:design
area:design-review
area:flows
area:infra
area:meta
area:security
area:sessions
area:webhook
area:workdir
security
type:bug
type:chore
type:meta
type:user-story
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
charles/claude-hooks#255
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
User story
As an operator running the designer fleet across multiple repos, I want each watched repo to pin its Penpot team in config, so that the designer never has to guess which team to work in — and so that
charles/claude-hooks→peon-manager,charles/proxmox-iac→ some-other-team, etc., stays explicit and auditable rather than inferred fromlist_teams.Today
skills/design-implement.mdstep 2 just says "find-or-create the Penpot file in the team's mockup project", and the agent callsmcp__penpot__list_teamsto pick one. On 2026-04-21, taskce585c20stopped at that step with 10 turns and $0.54 spent — the agent read a transit-json-encoded team list (~u41e41004-…) and never proceeded to create anything. Pinning the team in config removes the guess entirely.Acceptance criteria
Config schema
config/agents.jsongrows a top-levelpenpotblock:base_urlreplaces the hardcodedhttps://design.jacquin.appinapps/server/src/main.tsstartup so non-LAN deployments don't have to patch source.default_team_idis used as the fallback when a repo has no explicit entry (so new repos don't silently break the designer).penpotblock at all = loader proceeds silently withnull;penpot_mcp: truetypes continue to work but without per-repo pinning (legacy behavior).Loader + runner wiring
webhook-config.tsparses + validates thepenpotblock. UUIDs must look like UUIDs; unknown keys underteam_by_repolog a warning but don't fail the loader.agent-runner.tssurfacespenpot_team_id+penpot_team_namein the task prompt envelope when dispatching apenpot_mcpagent, resolved fromteam_by_repo[task.repo] ?? { team_id: default_team_id }./foreman/config+/agentsresponses include the effective Penpot team for transparency (read-only).Skill update
skills/design-implement.mdstep 2 changes from "find-or-create the Penpot file in the team's mockup project" to:Penpot team:line (legacy dispatch from an older service), the skill falls back tolist_teams+ picks the first. Logs a one-line "no team pinned — using fallback" warning in the handoff comment.Operator docs
CLAUDE.md§"Penpot MCP auth" gains a block on the per-repo team config, with a runbook for adding a new repo:designerPenpot user to it (owner/admin, the designer needs both to create files + export frames)..../#/settings/members?team-id=<uuid>).team_by_repo.<repo>entry toconfig/agents.json.Verification
webhook-config.test.ts— loader accepts the new block, rejects malformed UUIDs.agent-runner.test.ts— task envelope for apenpot_mcp: trueagent includes the effective team id/name when the repo is mapped.charles/claude-hooks→peon-manager, label-dispatch a new mockup ticket, confirm the resulting Penpot file lands in the right team (visible in the handoff deep-link URL path).Out of scope
design.jacquin.app-wide files between teams — we live with the Default-team mockups already accumulated.References
apps/server/src/agent-runner.ts::buildMcpSetup— where the Penpot MCP gets registered; the env var forwarding happens here.apps/server/src/main.ts::setPenpotMcpConfig— startup token load, hardcodes the base URL.skills/design-implement.mdstep 2 — the current "find team" prompt.ce585c20stuck onmcp__penpot__list_teamswith a valid response it couldn't turn into action.