Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changepacks/changepack_log_Hk3vT9pQw5LnZ2xJc7RmB.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"changes": {
"Cargo.toml": "Minor"
},
"note": "Offer /devup-retro when devup-mcp work is complete: the final completion report ends with one question in the user's language (\"작업이 완료되었습니다. 지금까지 진행한 내용을 개선하기 위해 /devup-retro 를 실행할까요?\"). The rule is contract identifier offer-devup-retro-in-final-report (developmentContract v5) and is stated in delivery-quality, the devfive-frontend, devup and devup-implementation-plan skills and the usage guide; results that mark completion (runtime-audit completion reportAllowed, screen-plan status reportAllowed, stack-diff zero drift on every layer) carry nextSuggestedAction with the ready message and the invocation that works in the workspace. Never on intermediate or failing results, never run unasked.",
"date": "2026-11-10T00:00:00.000000000Z"
}
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1115,6 +1115,8 @@ DevupUI가 audit 속성을 기본으로 제거하며 `DEVUP_AUDIT=1`이면 유

`/devup`과 같은 경로로 배포됩니다: `devup_skills install`이 `devup-retro` 스킬을 쓰고(Claude Code에서는 `.claude/skills/devup-retro/SKILL.md`가 곧 `/devup-retro`, Codex 등은 `.agents/skills`에서 이름으로 로드), OpenCode에는 스킬 본문으로 만든 `.opencode/command/devup-retro.md`도 씁니다. 설치하지 않은 워크스페이스에서는 MCP 프롬프트 `devup-retro`(인자 `scope`, `language`, 둘 다 선택; Claude Code에서는 `/mcp__<서버 이름>__devup-retro`)로 같은 본문을 받습니다. `devup_skills`의 `retro` 액션은 읽기 전용으로 설치된 빌드(`server`), 이 서버 프로세스가 처리한 devup-mcp 호출 기록(`callLog`: 도구·action·outputs·시각·성공 여부, 최대 200개, 인자 내용과 결과는 보관하지 않으며 재연결하면 비워짐), surface 목록, `.feedback/` 상태(`nextNumber`, index, 최근 기록)를 돌려줍니다. 명령 이름은 `crates/devup-mcp/src/server/skills/commands.rs`의 `retro_name!` 한 곳에서 정합니다.

완료 시 회고 제안: devup-mcp를 쓴 작업이 끝나면 에이전트는 최종 완료 보고의 마지막에 사용자 언어로 한 번 묻습니다. 한국어는 “작업이 완료되었습니다. 지금까지 진행한 내용을 개선하기 위해 /devup-retro 를 실행할까요?”, 그 외에는 같은 뜻의 영어 문장입니다. 스킬이 설치돼 있으면 `/devup-retro`, 아니면 MCP 프롬프트 형태 `/mcp__<서버 이름>__devup-retro`를 씁니다. 이 규칙은 계약 식별자 `offer-devup-retro-in-final-report`(developmentContract v5)와 delivery-quality의 “Final report: offer the retrospective”, devfive-frontend·devup·devup-implementation-plan 스킬의 최종 보고 단계, `devup://guide/usage`에 있습니다. 완료를 뜻하는 도구 결과에만 `nextSuggestedAction`(id, invocation, `message.ko`/`message.en`, 규칙)이 붙습니다: `devup_runtime_audit` completion의 `reportAllowed: true`, `devup_screen_plan` status의 `completion.reportAllowed: true`, `devup_stack_diff`의 네 layer 전부 checked + drift 0. export의 `deliverable.isFinal`과 `devup_ui_validate` 통과는 작업 중 여러 번 나오는 중간 결과라 붙지 않습니다. 완료된 작업당 한 번만 제안하고, 중간 호출·실패·미해결 상태에서는 제안하지 않으며, 사용자가 수락하기 전에는 실행하지 않습니다.

질문 도구에 호출당 개수 제한이 없으면(OpenCode `question`) 평평한 `questions` 목록을 한 번에 묻고, 제한이 있으면(Claude Code `AskUserQuestion`: 4) `maxQuestionsPerRound`(기본 4)로 나눈 `questionRounds`를 연달아 묻습니다.

## 읽기 전용·개인정보 보호
Expand Down
4 changes: 3 additions & 1 deletion crates/devup-mcp/src/server/commands/opencode-devup.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,9 @@ For Figma work, continue with the following branch after project intake:
--deny-warnings`, `bun tsc --noEmit` in each changed app and `bun test`
pass (`bun run test` adds cargo tarpaulin, which does not work on
Windows), devup_ui_validate has no errors, site completeness filled.
13. Finish with the status finalReport and summary.
13. Finish with the status finalReport and summary. When the work is complete,
end by offering /devup-retro once in the user's language ("작업이 완료되었습니다. 지금까지 진행한 내용을 개선하기 위해 /devup-retro 를 실행할까요?");
never after a failure, never run it unasked.

User-owned decisions, before or after confirm, use the runtime question tool.
Show the evidence table first. Keep table approval and individual decisions as
Expand Down
3 changes: 3 additions & 0 deletions crates/devup-mcp/src/server/completion_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,9 @@ async fn source_bound_static_checks_cannot_replace_figma_visuals() {
input.visual_environments.insert(comparison_id, serde_json::from_value(json!({"tsxResource":{"uri":"devup://artifact/test/tsx","sha256":"a".repeat(64)},"themePath":"devup.json","assetDirectory":"public/images","devupUiVersion":"test","fontManifest":[{"family":"Test","sha256":"b".repeat(64)}]})).unwrap());
let result = write(&input, &policy, &store, None).await.unwrap();
assert_eq!(result["stage"], "data-verified", "{result}");
// The one receipt that may be reported is the one that carries the offer.
assert!(super::super::skills::marks_completion("devup_runtime_audit", "completion", &result));
assert!(!super::super::skills::marks_completion("devup_runtime_audit", "ingest", &result));
assert_eq!(refresh(&input.project_root, &policy, &store).await.unwrap()["done"], true);
assert_eq!(result["dataVerificationScope"], "not-required");
// A syntactically present but unsigned empty inventory cannot remove all
Expand Down
12 changes: 9 additions & 3 deletions crates/devup-mcp/src/server/development_contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ pub(super) const REQUIREMENTS: &[&str] = &[
"canonical-semantic-assets",
"landing-detail-api-db-single-source",
"runtime-evidence-before-completion",
"offer-devup-retro-in-final-report",
];

pub(super) const COMPLETION_EVIDENCE: &[&str] = &[
Expand All @@ -48,7 +49,7 @@ pub(super) const COMPLETION_EVIDENCE: &[&str] = &[
pub(super) fn attach(result: &mut Value) {
if !result.is_object() { return; }
result["developmentContract"] = json!({
"version": 4,
"version": 5,
"guide": "devup://guide/usage#behavior-and-data-contracts",
"alwaysApplies": true,
"requirements": REQUIREMENTS,
Expand All @@ -66,11 +67,16 @@ mod tests {
attach(&mut result);
assert_eq!(result["developmentContract"]["alwaysApplies"], true);
assert_eq!(result["developmentContract"]["staticExportProvesApplicationBehavior"], false);
assert_eq!(result["developmentContract"]["version"], 4);
assert_eq!(result["developmentContract"]["version"], 5);
let requirements = result["developmentContract"]["requirements"].as_array().unwrap();
for required in ["route-owned-page-body", "devup-api-only", "stop-affected-api-gaps", "paired-e2e-and-native-figma-visuals"] {
assert!(requirements.contains(&json!(required)));
}
assert!(requirements.contains(&json!("offer-devup-retro-in-final-report")));
for term in ["Final report: offer the retrospective", "Ask once per completed task", "Never run it
yourself", "carries no offer", super::super::skills::RETRO_OFFER_FIELD] {
assert!(RULES.contains(term), "missing completion offer: {term}");
}
for term in ["keep-all", "grayscale", "layout.tsx", "count", "footer", "DB", "aria-current", "sidecar"] {
assert!(RULES.contains(term), "missing delivery policy: {term}");
}
Expand Down Expand Up @@ -136,6 +142,6 @@ mod tests {
unique.sort();
unique.dedup();
assert_eq!(unique.len(), REQUIREMENTS.len() + COMPLETION_EVIDENCE.len());
assert_eq!((REQUIREMENTS.len(), COMPLETION_EVIDENCE.len()), (20, 8));
assert_eq!((REQUIREMENTS.len(), COMPLETION_EVIDENCE.len()), (21, 8));
}
}
9 changes: 8 additions & 1 deletion crates/devup-mcp/src/server/handlers/devup_runtime_audit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@ impl DevupServer {
false,
))
};
let result = match input.action.as_str() {
let completion_root = input
.completion
.as_ref()
.map(|completion| completion.project_root.clone());
let mut result = match input.action.as_str() {
"plan" => {
let mut plan = input
.plan
Expand Down Expand Up @@ -77,6 +81,9 @@ impl DevupServer {
_ => return Err(invalid("action must be plan, ingest or completion.")),
}
.map_err(to_mcp_error)?;
// Only the completion receipt can say the application is finished.
let complete = skills::marks_completion("devup_runtime_audit", &input.action, &result);
self.offer_retro(&mut result, completion_root.as_deref(), complete);
Ok(tool_result(result))
}
}
3 changes: 3 additions & 0 deletions crates/devup-mcp/src/server/handlers/devup_screen_plan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ impl DevupServer {
{
prefer_bridge_reference_calls(&mut result);
}
// Status is done only after application completion was re-evaluated.
let complete = skills::marks_completion("devup_screen_plan", &input.action, &result);
self.offer_retro(&mut result, input.project_root.as_deref(), complete);
Ok(tool_result(result))
}
}
Expand Down
13 changes: 13 additions & 0 deletions crates/devup-mcp/src/server/handlers/devup_skills.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
use super::*;

impl DevupServer {
/// Adds the /devup-retro offer to a result that marks completion. Called
/// only by the tools whose result can mean "the work is finished".
pub(super) fn offer_retro(&self, result: &mut Value, project_root: Option<&str>, complete: bool) {
let lookup = skills::Lookup::new(
project_root,
self.output_policy.primary_root(),
self.client_name(),
);
skills::offer_retro(result, &lookup, complete);
}
}

#[tool_router(router = devup_skills_router, vis = "pub(super)")]
impl DevupServer {
#[tool(
Expand Down
4 changes: 3 additions & 1 deletion crates/devup-mcp/src/server/handlers/devup_stack_diff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ impl DevupServer {
&self,
Parameters(input): Parameters<StackDiffInput>,
) -> Result<CallToolResult, ErrorData> {
let result = stack_diff::run(input.project_root.as_deref(), &input.layers)
let mut result = stack_diff::run(input.project_root.as_deref(), &input.layers)
.await
.map_err(to_mcp_error)?;
let complete = skills::marks_completion("devup_stack_diff", "", &result);
self.offer_retro(&mut result, input.project_root.as_deref(), complete);
Ok(tool_result(result))
}
}
5 changes: 5 additions & 0 deletions crates/devup-mcp/src/server/skills/devfive-frontend/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,11 @@ Common coding conventions for DevFive frontend projects (puzzle-fit, girok-space

## Links, controls and completion evidence

End the final completion report by offering the retrospective once, in the user's
language ("작업이 완료되었습니다. 지금까지 진행한 내용을 개선하기 위해 /devup-retro 를 실행할까요?" / "The work is complete. Shall I run /devup-retro to turn this session's follow-up prompts into devup-mcp improvements?"; `/mcp__<server>__devup-retro` when the skill is not installed).
Ask once per completed task, never after an intermediate call or a failure, and never
run it unasked. A completion-state tool result carries the sentence as `nextSuggestedAction`.

`devup_figma_export` produces static visual markup. Its `interactiveCandidates`
are a review list, and `deliverable.isFinal` never proves working navigation or
forms. Resolve GNB, logo, footer, CTA, cards, “view all”, tabs and breadcrumbs
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,26 @@ replace the agreed CSS viewport, DPR or zoom. If the required capture viewport
cannot fit onscreen, use an independent automated browser context at that size;
do not change application layout, CSS zoom or thresholds to make a pane match.

## Final report: offer the retrospective

When the work is complete, end the final completion report with one question
offering the session retrospective, in the user's language:

- Korean: "작업이 완료되었습니다. 지금까지 진행한 내용을 개선하기 위해 /devup-retro 를 실행할까요?"
- otherwise: "The work is complete. Shall I run /devup-retro to turn this session's follow-up prompts into devup-mcp improvements?"

Use the invocation that works in this client: `/devup-retro` when the
`devup-retro` skill is installed, otherwise the MCP prompt form
`/mcp__<server>__devup-retro`. A tool result that marks completion carries the
ready sentence as `nextSuggestedAction` (`devup_runtime_audit` completion with
`reportAllowed`, `devup_screen_plan` status with `completion.reportAllowed`,
`devup_stack_diff` with every layer checked and zero drift). An export's
`deliverable.isFinal` grades generated source and carries no offer.

Ask once per completed task. Not after an intermediate tool call, a failed or
unresolved result, or a partial report, and not again once asked. Never run it
yourself: it starts only when the user says yes.

## Contract identifiers

Export replies carry `developmentContract` as identifiers only, to stay inside
Expand Down Expand Up @@ -329,6 +349,7 @@ before claiming completion. The installed copy of this document is
| `canonical-semantic-assets` | One asset registry, semantic file names, no duplicates or hash names |
| `landing-detail-api-db-single-source` | Landing and detail values come from the same API and DB records |
| `runtime-evidence-before-completion` | Completion is claimed from a runtime audit, not from the export or a screenshot |
| `offer-devup-retro-in-final-report` | The final completion report ends by offering `/devup-retro` once, in the user's language; it is never run unasked |

`completionEvidence`:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,12 @@ its computer-use setup yourself. Verify status and a small read before export.
design fixes requested, the excluded frames, the assumptions and the
dependencies line - and its one-line `summary`. Report every `fail`,
`not-run`, unresolved finding and assumption as what it is.
Then offer the retrospective once, in the user's language:
"작업이 완료되었습니다. 지금까지 진행한 내용을 개선하기 위해 /devup-retro 를 실행할까요?"
(otherwise "The work is complete. Shall I run /devup-retro to turn this session's follow-up prompts into devup-mcp improvements?";
`/mcp__<server>__devup-retro` when the skill is not installed). Only when
the work is complete, never after an intermediate call or a failure, and
never run it unasked.

Hard rules, after confirm:

Expand Down
6 changes: 6 additions & 0 deletions crates/devup-mcp/src/server/skills/devup/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,12 @@ Then run `bun run build`, `bun run lint`, `bun tsc --noEmit`
width (health, geometry, page, section, asset, interaction, screenshot,
diffs), unresolved findings with evidence, pending decisions taken,
assumptions, design fixes, exclusions, defaults and the dependencies line.
Then offer the retrospective once, in the user's language:
"작업이 완료되었습니다. 지금까지 진행한 내용을 개선하기 위해 /devup-retro 를 실행할까요?"
(otherwise "The work is complete. Shall I run /devup-retro to turn this session's follow-up prompts into devup-mcp improvements?";
`/mcp__<server>__devup-retro` when the skill is not installed). Only when
the work is complete, never after an intermediate call or a failure, and
never run it unasked.

Hard rules: visually verify every screen, section and asset at every drawn
width; never stop to wait, reorder the work; done = every required cell passes;
Expand Down
16 changes: 8 additions & 8 deletions crates/devup-mcp/src/server/skills/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@
"documents": [
{
"path": "SKILL.md",
"bytes": 31428,
"sha256": "e4729816c355ee065c1a5908516a68c95c9bca59131c62958404ce94db30d320"
"bytes": 32009,
"sha256": "3b40ffaecfcab15bf531bf84197a5c0c377392ed57ca8ad888f237e415acf57d"
},
{
"path": "references/critical-rules.md",
Expand All @@ -76,8 +76,8 @@
},
{
"path": "references/delivery-quality.md",
"bytes": 25551,
"sha256": "b5e6013167c80f785b93ae4c80b4ad2f300a381610065a7fcf183524f79e48a3"
"bytes": 26870,
"sha256": "ee1dd0b19c1a4bff42709af86e19e15496ccc2f22fa99b60ffa9490db2574362"
},
{
"path": "references/animation.md",
Expand All @@ -99,8 +99,8 @@
"documents": [
{
"path": "SKILL.md",
"bytes": 45398,
"sha256": "90ced638e1f3ad023bf991bc69872fae18933431cb3f5302f023cb716156bbe4"
"bytes": 45897,
"sha256": "ddbfcb3588c4c61c1e867abae24d062f4a88ed838fd47e7917d98edcfd498e2c"
}
],
"sourceUrl": "https://github.com/dev-five-git/devup-mcp/blob/HEAD/crates/devup-mcp/src/server/skills/devup-implementation-plan",
Expand All @@ -117,8 +117,8 @@
"documents": [
{
"path": "SKILL.md",
"bytes": 24646,
"sha256": "41e42e8aa489c4d8b51fcfbe02fa6cc53a72dfdab2713cd284b656666c41c58d"
"bytes": 25151,
"sha256": "52c926b03727b9b05bd09a2a8875f1dbbb71c253ef60cb4054434f4d600b5fdc"
}
],
"sourceUrl": "https://github.com/dev-five-git/devup-mcp/blob/HEAD/crates/devup-mcp/src/server/skills/devup",
Expand Down
Loading
Loading