Activate a DuploCloud project context.
50
55%
Does it follow best practices?
Impact
—
No eval scenarios have been run
Advisory
Suggest reviewing before use
Optimize this skill with Tessl
npx tessl skill review --optimize ./skills/activate_project/SKILL.mdAlways prefix active workspace, project, or ticket names with a 🟢 emoji. This applies everywhere an active/selected name is displayed — auto-select messages, confirmation prompts, health tables, and list items.
Example:
Auto-selecting 🟢 aws-sample-workspace — it's the only workspace available.
In lists, only the currently active item gets the 🟢 prefix.
Follow these steps in order:
Read .duplocloud/state.toon (file may not exist). Note workspace_id, project_id, project_name if present.
Call duplo-helpdesk::Workspaces_get_available to get the list of available workspaces.
If the call fails with an auth or connection error, stop and tell the user:
"Cannot reach the duplo-helpdesk MCP server. Ensure
DUPLO_TOKENis exported and the server is running."
If the call returns an empty list, tell the user:
"It looks like you don't have any workspaces set up yet. Please create one in the DuploCloud portal first." Then stop.
If only one workspace is returned: auto-select it and tell the user:
"Auto-selecting 🟢 <workspace name> — it's the only workspace available." Capture its
idasworkspace_id.
If multiple workspaces and workspace_id is present in state:
workspace_id exists in the returned list."You're currently connected to 🟢 <workspace name>. Would you like to continue with this workspace? (y/n)"
If workspace_id is absent from state: show the workspace list (Step 1a).
Show a numbered list using only the workspace name (no raw IDs). If a workspace matches the workspace_id currently in state, prefix it with 🟢:
Here are your available workspaces:
1. 🟢 <name> ← currently active
2. <name>
...Ask: "Which workspace would you like to use?"
Capture the selected workspace's id as workspace_id (store internally, do not show to the user).
If the newly selected workspace differs from what was in state: clear project_id and project_name (the old project belongs to the old workspace).
Call duplo-helpdesk::Projects_list with workspaceId = workspace_id.
TOON parsing — do this before any case logic:
The response is TOON-encoded. Strip the toon| prefix and parse JSON. The project list is under d.itms (not a top-level array). itms will be either:
{ "_sch": [...], "_dat": [[...], ...] } → expand by zipping each _dat row with _sch to produce plain objects.TOON key map for project fields: i = id, n = name, desc = description, act = isActive. Use these when reading project properties.
After expanding, projects is a plain list of objects. Proceed with case logic below.
If the list is empty: tell the user "No projects found in this workspace. Please create a project in the DuploCloud portal first." and stop.
Case A — only one remote project:
i matches project_id in local state → tell the user:
"Auto-selecting 🟢 <n> — it matches your saved session." Proceed to Step 4.
"Auto-selecting 🟢 <n> — it's the only project available." Capture
iasproject_idandnasproject_name. Proceed to Step 4.
Case B — multiple remote projects, project_id present in state AND found in remote list (match on i):
"Active project: 🟢 <project_name>. Would you like to continue with this project or select a different one?
- Continue with <project_name>
- Select from list"
Case C — multiple remote projects, project_id absent OR not found in remote list:
Continue to Step 3.
Show the user a numbered list. If a project matches the project_id currently in state, prefix it with 🟢:
Available projects:
1. 🟢 <name> — <description> ← currently active
2. <name> — <description or "no description">
...Ask: "Which project would you like to activate?"
Wait for selection. Capture:
i field (TOON for id) → project_idn field (TOON for name) → project_nameIf DUPLO_AGENT_MODE=false or not set (local agent mode): call these in parallel with the state write (one tool-call group):
duplo-helpdesk::Workspaces_get_personas with id = workspace_idduplo-helpdesk::Workspaces_get_scopes with id = workspace_idduplo-helpdesk::Workspaces_get_skills with id = workspace_id — workspace-specific skills via personasduplo-helpdesk::Workspaces_get_skills_built_in_files (no parameters) — platform built-in skill filesduplo-helpdesk::Projects_get with id = project_idWrite all of the following in the single Bash flush:
.duplocloud/state.toon — workspace + project state~/.duplocloud/workspace_context.json — with fetched_at set to now (ISO 8601 UTC), personas, scopes, skills, and project data. See Local Agent Context section in CLAUDE.md for schema.~/.duplocloud/skills/<skillName>/<path> — for each entry from Workspaces_get_skills_built_in_files write content to the corresponding path. For each workspace skill with non-empty skillMd write to ~/.duplocloud/skills/<name>/SKILL.md. Create ~/.duplocloud/skills/ directory first.Write .duplocloud/state.toon silently using bash, preserving any existing active_ticket_name and tickets fields if the workspace has not changed:
workspace_id: <workspace_id>
project_id: <project_id>
project_name: <project_name>Create the .duplocloud/ directory first if it does not exist.
Call duplo-helpdesk::Projects_get with id = project_id.
From the response extract:
spec.content → spec_content (string, may be blank or absent)spec.metaData.approvalState → spec_state:
"Approved" → Approvedplan.content → plan_content (string, may be blank or absent)plan.metaData.approvalState → plan_state (same logic as spec)execution.stages → stages (full array; store for use in Steps 8–12)execution.version → execution_versionhas_execution_tasks = true if any stage in stages has at least one taskDisplay the health table:
Project: 🟢 <project_name>
Artifact Status Spec <spec_state> Plan <plan_state> Tasks <N tasks ready / None>
Based on the health data, determine the next action:
Case 1: Execution tasks already exist (has_execution_tasks = true)
→ Proceed to Step 7b (show full menu) — users can work on tasks while refining spec/plan.
Case 2: No execution tasks yet (has_execution_tasks = false)
→ Based on spec/plan states, suggest the next action:
| Condition | Prompt |
|---|---|
| Spec Not started | "This project doesn't have a spec yet. Would you like to start the AI Planner? (y/n)" → if y, follow skills/ai_planner/SKILL.md |
| Spec Draft | "There's a spec draft in progress. Would you like to continue with the AI Planner to refine or confirm it? (y/n)" → if y, follow skills/ai_planner/SKILL.md |
| Spec Approved, plan Not started or Draft | "Spec is approved. Would you like to continue with the AI Planner to build the plan? (y/n)" → if y, follow skills/ai_planner/SKILL.md |
| Both Approved | Proceed to Step 7b (show full menu) |
If the user declines any prompt: stop.
Execute this step when both spec and plan are approved (regardless of whether execution tasks exist).
Ask:
"Spec and plan are approved. What would you like to do?
- Edit spec
- Edit plan
- Work on execution tasks
- Done"
/duplo:write_spec to edit the spec." Then stop./duplo:write_plan to edit the plan." Then stop.has_execution_tasks:
skills/stage_tasks/SKILL.md (project is already active, so Step 0a is skipped — jump directly to Step 0b). After stage_tasks completes, the skill ends./duplo:ai_planner to generate stages and tasks first." Then stop.Once a project is active, the user can run:
| Command | What it does |
|---------|-------------| | /duplo:ai_planner | Run the AI Planner to write or refine spec, plan, and tasks |
| /duplo:write_spec | Write or update the project spec |
| /duplo:write_plan | Write or update the implementation plan |
| /duplo:activate_ticket | Pick up a ticket under this project |
| /duplo:stage_tasks | Manage execution stages and tasks — list, add, edit, delete, create tickets (jumps to stage_tasks skill) |
| /duplo:clear_canvas | Explicitly reset the spec, plan, and canvas files (requires confirmation) |
6a46510
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.