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
1 change: 1 addition & 0 deletions src/agent/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ export async function startSession(options: SessionOptions): Promise<void> {
"mcp__marvin-governance__get_dashboard_sprint_summary",
"mcp__marvin-governance__run_doctor",
"mcp__marvin-governance__check_project_health",
"mcp__marvin-governance__get_started",
...pluginTools.map((t) => `mcp__marvin-governance__${t.name}`),
...codeSkillTools.map((t) => `mcp__marvin-governance__${t.name}`),
],
Expand Down
55 changes: 55 additions & 0 deletions src/agent/tools/doctor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import type { SourceManifestManager } from "../../sources/manifest.js";
import type { MarvinProjectConfig } from "../../core/config.js";
import { runDoctorScan, runDoctorFix } from "../../doctor/engine.js";
import { runHealthCheck } from "../../doctor/health/engine.js";
import { buildOnboardingGuide } from "../../doctor/health/onboarding.js";

export interface DoctorToolOptions {
config?: MarvinProjectConfig;
Expand Down Expand Up @@ -105,5 +106,59 @@ export function createDoctorTools(
},
{ annotations: { readOnlyHint: true } },
),

tool(
"get_started",
"Get a tailored onboarding guide for the project. Inspects current state (artifacts, sources, config) and returns an ordered checklist of recommended setup steps with completion status. Methodology-aware (SAP AEM vs generic agile).",
{},
async () => {
if (!options?.config || !options?.marvinDir) {
return {
content: [
{
type: "text" as const,
text: "Onboarding unavailable: project config or marvinDir not initialized.",
},
],
isError: true,
};
}

const { config, marvinDir, manifest } = options;

// Scan manifest before building guide
if (manifest) {
try {
manifest.scan();
} catch {
// Non-fatal
}
}

try {
const guide = buildOnboardingGuide({ store, config, manifest, marvinDir });

return {
content: [
{
type: "text" as const,
text: JSON.stringify(guide, null, 2),
},
],
};
} catch (err) {
return {
content: [
{
type: "text" as const,
text: `Onboarding error: ${err instanceof Error ? err.message : String(err)}`,
},
],
isError: true,
};
}
},
{ annotations: { readOnlyHint: true } },
),
];
}
147 changes: 147 additions & 0 deletions src/doctor/health/onboarding.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
import type { HealthContext } from "./types.js";

export interface OnboardingStep {
order: number;
title: string;
description: string;
tool?: string;
done: boolean;
}

export interface OnboardingGuide {
projectName: string;
methodology: string;
phase?: string;
status: "empty" | "getting-started" | "in-progress";
steps: OnboardingStep[];
summary: string;
}

/** Inspect project state and produce a tailored onboarding guide. */
export function buildOnboardingGuide(ctx: HealthContext): OnboardingGuide {
const counts = ctx.store.counts();
const totalArtifacts = Object.values(counts).reduce((sum, n) => sum + n, 0);
const methodology = ctx.config.methodology ?? "generic-agile";
const isAem = methodology === "sap-aem";
const phase = ctx.config.aem?.currentPhase;

const hasSources = (ctx.manifest?.list()?.length ?? 0) > 0;
const pendingSources = ctx.manifest?.list("pending")?.length ?? 0;
const hasActions = (counts["action"] ?? 0) > 0;
const hasEpics = (counts["epic"] ?? 0) > 0;
const hasSprints = (counts["sprint"] ?? 0) > 0;
const hasFeatures = (counts["feature"] ?? 0) > 0;
const hasUseCases = (counts["use-case"] ?? 0) > 0;
const hasJira = !!ctx.config.jira?.projectKey?.trim();

const steps: OnboardingStep[] = [];
let order = 1;

// Step 1: Ingest source documents
steps.push({
order: order++,
title: "Ingest source documents",
description:
pendingSources > 0
? `${pendingSources} source file(s) in .marvin/sources/ are ready for processing. Set the PO persona and ingest them to extract requirements, use cases, and initial artifacts.`
: hasSources
? "All source files have been processed."
: "No source files found. Add documents (PDF, Markdown, or text) to .marvin/sources/ to begin processing.",
tool: "set_persona",
done: pendingSources === 0 && hasSources,
});

// Step 2: Define scope (methodology-specific)
if (isAem) {
steps.push({
order: order++,
title: "Define extension use cases",
description:
"As PO, create use cases (UC-xxx) that describe business scenarios requiring SAP BTP extension. Classify each by extension type (in-app, side-by-side, hybrid) and priority.",
tool: "create_use_case",
done: hasUseCases,
});
} else {
steps.push({
order: order++,
title: "Define features",
description:
"As PO, create features (F-xxx) that describe the product capabilities to build. Set priorities and acceptance criteria.",
tool: "create_feature",
done: hasFeatures,
});
}

// Step 3: Capture decisions and actions
steps.push({
order: order++,
title: "Capture key decisions and actions",
description:
"Record important decisions (D-xxx) with rationale and create action items (A-xxx) for work that needs to happen. Set owners and due dates on actions.",
tool: "create_decision",
done: (counts["decision"] ?? 0) > 0 && hasActions,
});

// Step 4: Break down into epics
steps.push({
order: order++,
title: "Break work into epics",
description: isAem
? "As TL, create tech assessments for approved use cases, then break extension designs into implementation epics (E-xxx)."
: "As TL, break approved features into implementation epics (E-xxx) with effort estimates.",
tool: "create_epic",
done: hasEpics,
});

// Step 5: Set up Sprint 0
steps.push({
order: order++,
title: "Set up Sprint 0",
description:
"As DM, create a Sprint 0 to organize bootstrapping work: infrastructure provisioning, CI/CD setup, backlog refinement, and ceremony scheduling. Sprint 0 is not a regular sprint — it's a variable-duration bootstrapping phase that ensures the team is ready for Sprint 1.",
tool: "create_sprint",
done: hasSprints,
});

// Step 6: Configure Jira integration
steps.push({
order: order++,
title: "Configure Jira integration",
description:
"Add jira.projectKey to .marvin/config.yaml to enable bidirectional sync. This allows pushing artifacts to Jira and pulling sprint progress back.",
done: hasJira,
});

// Step 7: Run health check
steps.push({
order: order,
title: "Run a health check",
description:
"Use check_project_health to verify governance setup is complete. It will flag any missing configuration or unfinished setup steps.",
tool: "check_project_health",
done: false, // Always suggest running this
});

const doneCount = steps.filter((s) => s.done).length;
const status: OnboardingGuide["status"] =
totalArtifacts === 0
? "empty"
: doneCount < steps.length - 1
? "getting-started"
: "in-progress";

const pending = steps.filter((s) => !s.done);
const summary =
pending.length === 0
? "Project setup is complete. All onboarding steps are done."
: `${doneCount} of ${steps.length} steps complete. Next: ${pending[0].title}.`;

return {
projectName: ctx.config.name,
methodology,
phase,
status,
steps,
summary,
};
}
8 changes: 8 additions & 0 deletions src/personas/builtin/delivery-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,14 @@ export const deliveryManager: PersonaDefinition = {
- Monitor project health and flag risks early
- Create meeting notes and ensure action items are assigned

## Sprint 0
When a project has work items but no sprints, proactively suggest creating a **Sprint 0** — a variable-duration bootstrapping phase (not a regular time-boxed sprint). Sprint 0 should cover:
- **Infrastructure & provisioning**: CI/CD, repositories, cloud services, dev environments
- **Backlog refinement**: Transition from features to epics with acceptance criteria and estimates
- **Ceremony scheduling**: Define cadence for standups, refinement sessions, and reviews
- **Integration setup**: Configure Jira, Confluence, or other tool connections
Sprint 0 ends when the team is ready to start Sprint 1 with a refined backlog and working infrastructure.

## Communication Style
- Process-oriented but pragmatic
- Focus on status, risks, and blockers
Expand Down
9 changes: 8 additions & 1 deletion src/plugins/builtin/sap-aem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,14 @@ export const sapAemPlugin: MarvinPlugin = {
- Advance phases only when gate conditions are met (soft enforcement — warnings, not blocks).
- Generate extension portfolio reports for stakeholder updates.
- Generate tech readiness reports to identify BTP service gaps.
- Track risks via actions and questions. Flag unresolved items before phase gates.`,
- Track risks via actions and questions. Flag unresolved items before phase gates.

**Sprint 0 for AEM Projects:**
When setting up Sprint 0, also include AEM-specific bootstrapping:
- **Phase gate preparation**: Define soft gate checklists with readiness criteria for each AEM phase transition.
- **Tech assessment prerequisites**: Ensure BTP service access, extension point documentation, and sandbox environments are provisioned.
- **Iterative loop definitions**: Map the iterative loops between Assess Use Case ↔ Assess Technology ↔ Define Solution phases.
- **Extension design templates**: Prepare architecture pattern templates for in-app, side-by-side, and hybrid extensions.`,

"*": `This project uses the **SAP Application Extension Methodology (AEM)** — a 3-phase approach for building extensions on SAP BTP:

Expand Down
Loading
Loading