# Core Concepts
Source: https://docs.modelcode.ai/core-concepts
Morph mental model and terminology
Morph structures the modernization process as a series of well-defined stages, guiding teams from initial project setup all the way to delivering production-ready pull requests. This page explains the key terms used throughout each phase of that journey.
## Table of Contents
* [tl;dr](#tldr)
* [Core Concepts](#core-concepts)
* [Project](#project)
* [Repositories and Roles](#repositories-and-roles)
* [Build Environment](#build-environment)
* [Project Spec](#project-spec)
* [Milestone](#milestone)
* [Task](#task)
* [Rules](#rules)
* [Functional Testing](#functional-testing)
* [Project Knowledge](#project-knowledge)
* [Wiki](#wiki)
* [Daemon Pool](#daemon-pool)
* [Collaboration](#collaboration)
* [Upstream Sync](#upstream-sync)
* [Visual Diagrams](#visual-diagrams)
* [Glossary](#glossary)
## tl;dr
Morph turns your migration into a step-by-step pipeline:
1. Create a [**Project**](#project) (pick your repo(s) and assign [roles](#repositories-and-roles))
2. Choose a [**Build Environment**](#build-environment) (cloud or self-hosted)
3. Define your [**Project Spec**](#project-spec) (what should change & how)
4. Review and approve the [**Project Spec**](#project-spec)
5. Pick a [**Validation Level**](/setup/validation-level), then — at High — complete [**Project Setup**](#lifecycle-setup) in chat: lifecycle scripts, env vars, and an end-to-end validation
6. Generate a **Roadmap** of [**Milestones**](#milestone)
7. Execute each [**Milestone**](#milestone). During execution, Morph dynamically generates [**Tasks**](#task) so progress is transparent and each deliverable is verifiable.
8. Once milestone tasks are completed and verified, Morph produces a production-ready PR for that milestone.
Each concept builds on the previous one, so decisions stay traceable from high-level goals down to individual code changes.
## Core Concepts
### Project
A **Project** is the top-level container for a modernization effort. It defines:
* Which repositories are in scope and their roles in the migration
* Which branch strategy to use for generated code (feature branch)
* The operational boundary for the [Project Spec](#project-spec), [milestones](#milestone), and [rules](#rules)
In practice, a project is where Morph keeps the full migration context from initial setup to final PR delivery.
Morph Project creation
Some common use cases:
* Modernizing a legacy Flask-based application to FastAPI
* Rewrite C++ CLI using Rust
* Java application version upgrade
* Migrating a backend and its shared library together
### Repositories and Roles
A project can contain **one or more repositories**. Each repository has a defined role in the migration:
| Role | Description |
| ------------------------ | ---------------------------------------------------------------- |
| **Modified** | An existing repository that will be transformed during migration |
| **New** | A new repository created as part of the migration |
| **Reference Only** | A repository included for context but not modified |
| **One-to-One Migration** | Direct migration from one repository to another |
When creating a project, you select repositories and set an **origin branch** for each. The project also has a shared **feature branch** (prefixed with `morph-`) where generated code is committed.
The **Project Overview** — part of the Project Spec flow — captures the full picture: which repos you start with, which repos you end with, and each repo's modernization role.
### Build Environment
The **Build Environment** defines how your project builds, runs, and tests. This is configured during onboarding and is required before Morph can validate and execute migrations.
There are two options:
* **Cloud** — Morph provides a cloud-based build environment for projects with publicly accessible dependencies
* **Self-hosted Daemon** — A lightweight binary you run on your own infrastructure, necessary when your project depends on private registries, internal APIs, or on-premise services
### Lifecycle Setup
Each project has a **Lifecycle Setup** — the configuration that tells Morph how to actually run your application:
* **Scripts** — Ordered shell scripts that install dependencies, build, run, health check, and test the application
* **Environment variables** — Variables your application needs at build or runtime, with optional encryption for secrets
* **Lifecycle document** — A markdown overview describing the application architecture and how scripts fit together
* **Validation** — An end-to-end run that executes each script in sequence to confirm everything works
You don't write this by hand. During the **Project Setup** onboarding stage, an agent discovers it with you in [Knowledge chat](/customization/project-knowledge) — proposing scripts, asking about what it can't infer, and running the lifecycle end to end to prove it works. Project Setup runs at the **High** [validation level](/setup/validation-level) only.
Morph maintains separate lifecycle configurations for the **origin** (source) and **target** (destination) sides of the migration. The origin is set up during Project Setup; the target is discovered automatically during the foundation milestone.
How the lifecycle is set up in chat, reviewed, and validated
### Project Spec
The **Project Spec** is the source-of-truth document for what "done" means. It captures migration requirements before implementation begins.
You review and approve it in the **Project Knowledge** drawer on the **Roadmap** (under **Modernization** → **Project Knowledge**): select **Project Spec** in the tree and use **Knowledge chat**. The drawer opens automatically the first time the spec is ready.
Walkthrough: refine with chat, Auto-review, and approve
Typical contents include:
* Target stack
* High-level migration plan
* Key design decisions
* Project overview (repos at start, repos at end, and their roles)
* Testing strategy
Project Spec in Project Knowledge
The Project Spec must be approved before Morph generates the roadmap. You can keep refining it with Knowledge chat afterwards — once milestone planning has run, those edits apply to future milestones.
### Milestone
A **Milestone** is a coherent, reviewable chunk of migration work. Milestones are organized in a dependency graph — independent milestones can execute in parallel, while dependent milestones wait until their prerequisites are merged.
* Functionally meaningful (not arbitrary file splits)
* Small enough to review safely
* Dependency-aware: independent milestones run in parallel for faster delivery; dependent milestones stay locked until prerequisites merge
Each completed milestone produces a Pull Request for your review. When a milestone merges, sibling milestone branches that share dependencies may be flagged for an automatic **rebase** to stay current with the feature branch.
The milestone lifecycle, dependencies, parallel execution, and rebase
### Task
A **Task** is the smallest executable unit inside a milestone. Tasks translate milestone intent into specific implementation actions.
Tasks usually map to one of:
* File/module creation or migration
* Endpoint or data-model implementation
* Test implementation
* Refactor/fix work
### Rules
**Rules** are custom instructions that apply across all milestones. They encode your team's coding standards, library preferences, and patterns so that Morph follows them consistently throughout the migration.
Rules can be added, edited, or removed at any point during the migration.
### Functional Testing
**Functional Testing** verifies that migrated code behaves identically to the original by comparing real outputs side by side. Morph automatically generates, runs, and validates these tests as part of the milestone lifecycle — no manual test authoring required.
Functional testing supports multi-repo projects and covers three types of applications:
* **API testing** — Compares HTTP responses (status codes, response bodies) between origin and target for each endpoint
* **CLI testing** — Compares exit codes and stdout/stderr output between origin and target for each command
* **UI testing** — Captures screenshots and video recordings of the target application's frontend, with optional side-by-side comparison against the origin
Results are surfaced per-milestone (as a test summary on each milestone card) and in a project-level **Validation Hub** with dedicated **API/CLI**, **UI** (split into **Tests** and **QA Agent** sub-tabs), and **Lifecycle** tabs — the last of these reports install/build/run/test script results.
How functional tests are generated, verified, and reported
### Project Knowledge
**Project Knowledge** is the in-app drawer on the **Roadmap** where structured context lives together: **Project Spec**, **milestones**, **wikis**, and **rules**, plus **Knowledge chat**. Agents read this context during work and write updates back (often as new or revised wiki pages). Approving the [Project Spec](#project-spec) is one important use of this drawer; everything else you can do there — imports, rules, diffs, milestone text — is covered in [Project Knowledge](/customization/project-knowledge).
Project Knowledge serves two purposes:
* **Agent-to-agent knowledge transfer** — When one agent discovers a pattern or makes an architectural decision, it writes that knowledge back. Later agents read it and stay consistent.
* **User-to-agent guidance** — You can add documentation, coding standards, or design decisions at any time. The content you provide is broken down into structured wiki pages and rules that agents can consume efficiently.
### Wiki
A **Wiki** page is a piece of project knowledge stored with your project (shown under **Wikis** in Project Knowledge). Wikis capture architecture decisions, design patterns, integration notes, and other context that agents reference during execution. Unlike rules, wikis are treated as informational context rather than hard requirements.
### Daemon Pool
When using a [Self-hosted Daemon](/setup/build-environment/self-hosted-daemon), daemons are organized into **pools** — shared groups of machines that serve one or more projects. During Build Environment setup you either **join an existing pool** or create a new one. Any org member with project access can run work on the project's pool without needing their own personal daemon.
Each daemon in a pool reports its status in real time: **Available** (ready), **Busy** (running a job), or **Offline** (disconnected). A single daemon can serve several projects concurrently and runs more than one piece of work at once, and spreads work across the pool — so to add capacity, add a machine. When every daemon in a pool is fully occupied, starting new milestone and ad-hoc work is refused until one frees up. **Knowledge chat** and **Code Review chat** are exempt from this capacity gate — you can always start a chat session even when executions have filled the pool.
### Collaboration
Multiple team members can review the same milestone at the same time. Each reviewer gets their own independent [review chat session](/migration/code-review-chat#collaboration), so conversations and issue triaging don't collide. When one reviewer resolves an issue or the agent applies a fix, the change is propagated to other active reviewers' workspaces.
### Upstream Sync
As your team continues pushing to the repository's mainline during the migration, can incorporate those changes through an **upstream sync**. This creates a sync milestone that integrates mainline changes into the feature branch and rebases affected milestone branches. See [Git Strategy — Upstream Sync](/setup/build-environment/git-strategy#upstream-sync) for details.
## Visual Diagrams
### Concept Relationship Diagram
```mermaid theme={null}
flowchart TD
A[Project] --> B[Repositories & Roles]
A --> C[Build Environment]
C --> D[Project Spec]
B --> D
D --> L[Project Setup / Lifecycle]
L --> E[Milestone Plan / Roadmap]
E --> F[Tasks]
E --> H[Functional Tests]
F --> G[PR / Merge]
H --> G
I[Project Knowledge] --> E
I --> F
F -.->|writes back| I
D --> I
```
## Glossary
| Term | Definition |
| ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [Project](#project) | Top-level modernization container for repos, branch strategy, and all migration artifacts. |
| [Repository Role](#repositories-and-roles) | The function a repository serves in the migration (Modified, New, Reference Only, One-to-One). |
| [Build Environment](#build-environment) | Configuration for how the project builds, runs, and tests — cloud or self-hosted. |
| [Lifecycle Setup](#lifecycle-setup) | Project-level configuration containing scripts, environment variables, and a lifecycle document. Maintained separately for origin and target. |
| Project Setup | The onboarding stage — and the Project Knowledge branch — where an agent discovers and validates the lifecycle with you in chat. Runs at the High validation level only. |
| [Project Spec](#project-spec) | Source-of-truth for what the migration must produce (also called Instructions). [Review and approve](/setup/reviewing-project-spec) in the Project Knowledge drawer using chat. |
| [Milestone](#milestone) | Reviewable chunk of migration work with dependencies. Independent milestones run in parallel; dependent milestones wait. |
| [Task](#task) | Smallest actionable implementation unit within a milestone. |
| [Rules](#rules) | Custom instructions encoding team standards, applied across all milestones. |
| [Functional Testing](#functional-testing) | Auto-generated tests that compare origin and target behavior side by side. Covers API, CLI, and UI testing. Reported in the Validation Hub. |
| Validation Hub | Project-level dashboard for functional test and lifecycle script results, with API/CLI, UI, and Lifecycle tabs. |
| [Project Knowledge](#project-knowledge) | Roadmap drawer listing Project Spec, milestones, wikis, and rules, with Knowledge chat — the UI for the structured context agents read from and write to. |
| [Wiki](#wiki) | Project knowledge page under Wikis in Project Knowledge — architecture decisions, patterns, and integration notes. |
| [Daemon Pool](#daemon-pool) | Shared group of ModelDaemons that serve one or more projects. Work is routed across available daemons; chats are exempt from execution capacity limits. |
| [Collaboration](#collaboration) | Per-user review chat sessions that allow multiple reviewers to work on the same milestone simultaneously. |
| [Upstream Sync](#upstream-sync) | Incorporating mainline changes into the migration feature branch and rebasing affected milestone branches. |
| Rebase Required | A milestone state indicating its branch must incorporate newly merged sibling milestone code before it can be merged. |
| Roadmap | The main screen in the Morph Platform listing the project's milestones, with other project entities available via sidebar. |
| Project Overview | Summary of repos at start and repos at end, including each repo's modernization role. Part of the Project Spec. |
# Commenting
Source: https://docs.modelcode.ai/customization/commenting
Leave inline comments on project documents to collaborate with your team
You can leave comments directly on text in **Project Knowledge** to flag questions, suggest changes, or discuss decisions with your team. Comments are anchored to the text you select, highlighted inline, and visible to everyone on the project.
## Leaving a Comment
1. Open **Project Knowledge** from the Roadmap
2. Select any text in a document (Project Spec, milestone, wiki, or rule)
3. A context menu appears with **Add to context** and **Comment**. Click **Comment**
4. A popover form appears with the selected text quoted. Write your comment and submit with the **Comment** button or **Cmd+Enter** (Mac) or **Ctrl+Enter** (Windows/Linux)
The selected text is highlighted in amber. Your comment appears in the **Comments** panel.
## The Comments Panel
Click the **Comments** button in the toolbar to open the panel. It shows a badge with the number of open comments.
The panel has two sections:
* **Open** -- comments that still need attention
* **Resolved / Dismissed** -- comments that have been addressed
Each comment card shows the author, timestamp, the quoted text it references, and any replies.
Click an open comment to scroll the document to the highlighted text.
## Actions on Comments
Every team member can take the following actions on an open comment:
| Action | What it does |
| ------------------- | ---------------------------------------------------------------------- |
| **Resolve in chat** | Sends the comment and its context to Knowledge chat so can address it |
| **Done** | Marks the comment as resolved |
| **Reply** | Adds a threaded reply to the comment |
| **Dismiss** | Rejects the comment (marks it as not actionable) |
## @Mentions
Type `@` in the comment or reply textarea to mention a team member. An autocomplete dropdown shows team members filtered by name. Selecting a user inserts their name and sends them an email notification with the comment text and a link to the document.
## Outdated Comments
When the document content changes, comments whose selected text no longer exists in the document are marked **Outdated**. The highlight disappears and the comment card shows an outdated badge. This can happen when regenerates a spec or when someone edits a milestone.
Outdated comments still appear in the panel so you can review whether the concern was addressed by the change.
## Comment Indicators on the Tree
Documents that have open comments show an amber pulsing dot in the Project Knowledge tree. This makes it easy to scan which documents need attention without opening each one. The dot bubbles up to parent sections, so if any milestone has comments, the **Plan** section shows the dot too.
If a document also has a purple dot (requires attention for another reason, like an unapproved spec), the purple dot takes priority.
## Resolving via Chat
The **Resolve in chat** action is the fastest way to address a comment. It pastes the comment, the quoted text, and the document context into Knowledge chat. From there, can update the document, create a rule, or take whatever action is needed. Once the chat addresses it, come back and mark the comment **Done**.
## Best Practices
**Use comments for team discussion, not agent instructions.** If you want to change something, use the Knowledge chat directly. Comments are for collaborating with your teammates about what should change.
**Be specific in your selection.** Select the exact text your comment refers to, not an entire paragraph. This keeps highlights precise and makes it clear what you're commenting on.
**Resolve comments as you go.** Stale open comments add noise. Once a concern is addressed, mark it **Done** so the amber indicators clear and the panel stays useful.
# Editing Milestones
Source: https://docs.modelcode.ai/customization/editing-milestones
Adjust AI-generated milestones in Project Knowledge before approving them
Milestones are generated by AI based on your Project Spec and architecture. AI isn't perfect - sometimes you'll want to adjust a milestone before approving it. Edits happen in **Project Knowledge** via the chat panel: you describe the change, updates the milestone, and you review the diff before approving.
## Why Edit Milestones
### The AI Made a Mistake
The generated milestone might:
* Misunderstand which files are involved
* Propose an approach you disagree with
* Include something you want to exclude
### You Have Additional Context
You know things the AI doesn't:
* Specific business logic that needs special handling
* Dependencies that aren't obvious from the code
* Team preferences for how something should be done
### You Want to Adjust Scope
Sometimes a milestone is:
* **Too large** - remove parts you'll address separately
* **Too small** - add related work you want included
* **Missing something** - add requirements the AI overlooked
## When You Can Edit
You can edit a milestone when:
* It hasn't been approved yet (the agent hasn't started)
* It isn't locked - earlier milestones must be merged first, and the milestone must be unlocked for your plan
A locked milestone shows a **Locked** tag in the roadmap and a lock icon in the Knowledge drawer. You can still view its plan, but editing and approval are disabled.
While is re-validating an in-flight edit, a **Validating** tag appears on the milestone. Wait for it to clear before approving.
## What You Can Edit
The milestone view in Project Knowledge shows:
* **Title**
* **Description** - the detailed plan the agent uses to generate tasks
* **Relevant Files** - the files the milestone touches
* **Test Files** - the test files the milestone targets
All of these are updated through the chat panel. uses your edits to plan the tasks the agent runs, so changes to the description directly affect what gets built.
## How to Edit a Milestone
1. In the roadmap, expand the milestone and click **Milestone Plan** - Project Knowledge opens with the milestone selected.
2. On the right, review the current plan (title, files, description). On the left, the chat panel is ready for your request.
3. In chat, describe the change you want. For example:
> "Also include the email verification flow - migrate the `verify_email` endpoint and its token generation."
4. updates the milestone. A **Show Changes** toggle appears in the header - click it to see a diff of what was changed.
5. Iterate in chat until the plan reads the way you want.
6. When you're satisfied, click **Approve & Start** at the bottom of the drawer to launch the agent.
Use **Show Changes** to confirm the diff before approving. The Knowledge drawer keeps a running diff against the last update, so you can see exactly what your chat turns changed.
## Editing Tips
### Be Explicit About What You're Changing
If the original says:
> "Migrate the user authentication module to the new framework"
And you want to add session handling, ask for it explicitly:
> "In Milestone 2, also cover session management and the remember-me functionality."
### Remove Things You Don't Want
> "Remove the legacy admin panel from Milestone 3 - we'll handle it separately."
### Add Context the AI Lacks
> "For the payment processing milestone, note that we use a custom wrapper around Stripe in `lib/payments/stripe_wrapper.py`. Preserve its interface."
### Specify the Approach
> "For the AngularJS-to-React milestone, use functional components with hooks and React Context for state. Do not introduce Redux."
## Examples
### Adding Missing Functionality
**Ask in chat:**
> "Add the email verification flow to Milestone 2. The `verify_email` endpoint and its token generation should be migrated with full test coverage."
**Result:** the description grows to include verification work; the diff highlights the added lines.
### Narrowing Scope
**Ask in chat:**
> "In the utils migration milestone, limit the scope to `utils/string_helpers.py` and `utils/date_helpers.py`. Exclude `utils/legacy/` - we'll deprecate it instead of migrating."
### Specifying Approach
**Ask in chat:**
> "Convert the AngularJS controllers to React functional components with hooks. Do not use class components, and use built-in `useState`/`useContext` instead of Redux."
### Adding Requirements
**Ask in chat:**
> "When updating the database models to SQLAlchemy 2.0, add Alembic migrations for any schema changes and use async session management."
## After Approving
Once you click **Approve & Start**:
1. The milestone is locked from further edits.
2. The agent generates tasks from the approved plan and begins executing them.
3. Progress shows in the roadmap as tasks run.
Your last-approved plan is the authoritative instruction set for that milestone.
## When Not to Edit
### Minor Preferences
For small, recurring preferences (naming conventions, coding style, library choices), use [Rules](/customization/rules) instead. Rules apply to every milestone automatically.
### Fundamental Changes
If you realize the entire migration approach is wrong, editing individual milestones won't help. Revisit your **Project Spec** in Project Knowledge first.
# Project Knowledge
Source: https://docs.modelcode.ai/customization/project-knowledge
Structured project context in the Project Knowledge drawer — shared between agents and available for you to shape
**Project Knowledge** is where all structured project context lives in the product — the Project Spec, **Project Setup** (lifecycle scripts, environment variables, dependencies, Dockerfile), milestones, wikis, and rules — together with **Knowledge chat** for conversing with . You open it from the **Roadmap**: under **Modernization**, click **Project Knowledge**. During onboarding opens this drawer for you twice: first to **review and approve the Project Spec**, and then — at the High [validation level](/setup/validation-level) — to **go through Project Setup**, discovering and validating the application's lifecycle alongside the agent. Throughout the migration, agents read from and write to the same underlying knowledge; this UI is how you inspect and steer it.
## What Project Knowledge Is
Think of Project Knowledge as **structured context for Morph agents**, surfaced in a full-height drawer on the Roadmap. Every time an agent works on a task, the agent reads this knowledge to understand your project's architecture, conventions, how the application actually runs, and decisions already made. When an agent learns something new during execution — a pattern the agent discovered, an architectural decision, a fix to a startup script — the agent writes that back (often as wiki pages, rules, or lifecycle updates).
This is how agents pass knowledge to each other. Onboarding establishes how the app installs, builds, and runs (for projects on [High validation](/setup/validation-level)). Milestone 1 might establish a database access pattern. Milestone 5, handled by a different agent, reads both from the same project knowledge and follows them. The result is consistent code across your migration — and a configuration the agent can actually run — even when different agents handle different parts.
### What's Inside
Project Knowledge is organized in a tree:
| Type | What It Holds | How It's Used |
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
| **Project Setup** | Lifecycle for **Origin** and **Target** (scripts, environment variables, lifecycle document), **Acceptance Criteria**, plus either **Dependencies** (self-hosted) or **Dockerfile** (cloud) | Agents use the lifecycle to run, validate, and functionally test the application; acceptance criteria define quality gates |
| **Project Spec** | Goals, scope, and approach for the migration | Agents reference the Project Spec to stay aligned with the overall direction |
| **Milestones** | Detailed descriptions and scope for each migration step | Agents use milestone content to understand what each step requires |
| **Wiki** | Architecture docs, design decisions, patterns discovered during migration | Agents read wikis to understand project context and conventions |
| **Rules** | Coding standards, library preferences, explicit constraints — grouped as **Published**, **Draft**, or **Archived** | Agents follow published rules as hard requirements in every milestone |
### How Agents Use It
When an agent starts working on a milestone:
1. It reads the **Project Spec** to understand the migration's overall goals
2. It reads the **Project Setup** to know how to install, build, run, and health-check the app
3. It reads all **rules** to know which standards to follow
4. It reads relevant **wiki pages** to understand architecture and patterns
5. It reads the **milestone description** to know what to build
After execution, the agent writes back anything it learned — new patterns, architectural decisions, integration notes, and any lifecycle fixes it needed to make the app run — as wiki pages or as updates to the lifecycle configuration. That keeps project knowledge growing and more accurate over the course of the migration.
## Opening Project Knowledge
**During onboarding — Project Spec:** When your Project Spec finishes generating, the drawer opens with **Project Spec** selected so you can review and approve it.
**During onboarding — Project Setup:** After you approve the spec and pick the High validation level, the **Project Setup** stage on the Roadmap opens the drawer again with **Knowledge chat** seeded to start setup — the agent walks you through discovering and validating how your application installs, builds, runs, and is health-checked. See [Project Setup (Onboarding)](#project-setup-onboarding) below.
**Any time after that:** Go to the project's **Roadmap**. In the left **Modernization** column, click **Project Knowledge** to open the drawer. You can also open it from flows that link knowledge (for example, opening a rule, milestone, or lifecycle script in context).
## Project Setup (Onboarding)
**Project Setup** is the branch of the Project Knowledge tree that holds everything needs to actually *run* your application. It's also **where the Project Setup onboarding stage happens** — the agent collaborates with you in **Knowledge chat** to fill this branch in, then validates it end to end.
Project Setup runs only at the **High** validation level, after the Project Spec is approved. At Low and Mid, never builds or runs the origin application, so there is no origin lifecycle to set up. See [Validation Level](/setup/validation-level).
The branch is organized by side of the migration, mirroring the rest of project knowledge:
* **Origin** — How the source application builds and runs. Discovered together with you during onboarding and used as the behavioral baseline for [functional testing](/migration/functional-testing).
* **Target** — How the destination application builds and runs. Discovered automatically during the foundation milestone (Milestone 1) so the target side is ready before migration code starts landing.
* **Dependencies** and **Dockerfile** — Project-wide artifacts the agent builds during onboarding and keeps in sync as the project evolves.
Each origin/target entry contains three sub-items you can select in the tree:
| Sub-item | What it is |
| ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| **Scripts** | Ordered shell scripts — typically `install`, `build`, `run`, `healthcheck`, and `test` — that bring the app to a healthy, running state |
| **Environment Variables** | Variables and secrets the app needs at build or runtime, discovered from the codebase or set explicitly. Secrets are encrypted at rest |
| **Lifecycle Document** | A markdown overview describing the application's architecture, the execution order of scripts, and how each phase fits together |
### How Project Setup flows through this drawer
The **Project Setup** stage on the Roadmap routes you into the Project Knowledge drawer with the chat focused on lifecycle discovery. Until the agent has discovered something to show, the drawer is **chat only** — the tree and content pane appear once the configuration exists. From there:
1. The agent inventories your repository — framework, install/build/run commands, healthcheck signals, env vars and secrets, external service dependencies — and **reports back what it found** before writing anything.
2. It proposes the lifecycle **phases** (install / build / run / healthcheck / test, plus optional steps like `migrate` or per-service splits in multi-environment projects) and confirms them with you.
3. It registers the **scripts** and **environment variables**, asking you for any values it can't infer (service URLs, tenant-specific config). Credentials are requested with a **Provide Secret** card that encrypts the value immediately — never type a secret into the chat box.
4. It **executes the lifecycle end-to-end** to validate it actually works. On failure, it surfaces the failing phase, the last lines of output, and a proposed fix before retrying.
5. Once validation passes, the lifecycle is marked **Validated** and onboarding continues to **Generate Roadmap**. If the agent can't get it fully healthy, it asks you to confirm saving the configuration as **Draft — Needs Review** so you can correct it.
You can see this happen live in the drawer: the tree on the left shows the Project Setup branch filling in as the agent works, and the chat on the right is where you answer questions and approve choices.
### Lifecycle validation statuses
A status bar at the top of the Project Setup panel tells you whether your lifecycle is ready — and, when it isn't, what to do next. The statuses and what each one asks of you are covered in [Lifecycle Setup](/setup/build-environment/lifecycle-setup#validation-status).
### Editing the lifecycle later
**Scripts** and **environment variables** stay editable in the panel — use **Add Script**, **Add Variable**, and **Save Changes**. The **lifecycle document**, **Dockerfile**, and **Dependencies** are displayed read-only; the last two carry the hint *"Read-only — ask the chat to update this."* Change any of them by asking the chat.
Running validation always goes through the chat. **Re-validate** in the toolbar hands the run to the agent, so you can watch it work and answer questions mid-run.
Ask **Knowledge chat** whenever you'd rather have the agent work the change out itself. Typical asks:
```
The run script should bind to port 8080, not 3000.
Re-validate after the change.
```
```
Add a `migrate` script that runs `alembic upgrade head` before `run`.
```
```
DATABASE_URL should point at a local Postgres on localhost:5432
for validation. Save it as a regular env var, not a secret.
```
For a full walkthrough of the Project Setup chat flow, the panel sections, and validation states, see [Lifecycle Setup](/setup/build-environment/lifecycle-setup).
## Knowledge Chat
**Knowledge chat** is the chat panel on the right side of the Project Knowledge drawer. It is your primary way to interact with when working with project knowledge — onboarding, Project Spec review, lifecycle changes, wiki and rule management all happen here.
### Sessions
Knowledge chat supports multiple sessions. Use the session picker at the top of the chat panel to switch between existing conversations or start a **New chat**. Each session keeps its own history, so you can have separate threads for different topics (lifecycle tuning, architecture decisions, rule changes) without losing context.
Sessions may show which daemon they are running on (displayed as *"· on \"* next to the session name).
### Preparing and warmup
When you open Knowledge chat, may need a moment to prepare a sandbox on the daemon — allocating a workspace, cloning the repository, installing dependencies, and indexing the codebase. This warmup happens automatically and you can see its progress in the chat panel. After the first warmup, subsequent opens are faster because the environment is already cached.
### Session locking
Only one user can actively control a Knowledge chat session at a time. If a teammate already has an active session, you see a message naming the user who holds the lock. The session unlocks when that user finishes or their session times out after inactivity.
This prevents the agent from receiving conflicting instructions from multiple users at the same time. If you need to work in Knowledge chat while a teammate holds the lock, coordinate with them directly.
### Exclusive access and moving workers
Sometimes a Knowledge chat session needs exclusive access to the application process on the daemon (for example, to run lifecycle commands). If another job is already using that access on the same worker, your chat is **parked** — it waits for the other job to finish.
If the pool has another available daemon, offers a **Move to a free worker** option so your chat can continue on a different daemon without waiting.
### Pool capacity
Knowledge chat is **exempt** from the [daemon pool](/setup/build-environment/self-hosted-daemon#pool-capacity) execution capacity gate. You can start a Knowledge chat session even when all workers in the pool are busy with milestone or ad-hoc executions.
## Adding Your Own Knowledge
You can add context at any time. This is useful when you have documentation, design decisions, or standards that should know about from the start.
When you add content, it isn't stored as a single blob. breaks it down into structured **wiki pages** and **rules**, optimized for how agents consume it. A long design doc becomes focused, referenceable entries agents can query efficiently.
### Using the Chat
Use the **Knowledge chat** panel to talk to and create, update, or reorganize knowledge.
**To add documentation:**
1. Open **Project Knowledge** from the Roadmap (**Modernization** → **Project Knowledge**)
2. Open the chat panel if it is hidden
3. Describe what you want to add
For example:
```
We use the repository pattern for all database access.
Each entity has its own repository class that extends BaseRepository.
Repositories handle all SQL queries — services never write raw SQL.
Here's an example from our codebase:
class UserRepository(BaseRepository[User]):
async def find_by_email(self, email: str) -> User | None:
return await self.find_one({"email": email})
```
takes this and creates the appropriate wiki pages and rules so that every agent follows this pattern.
### Dragging in Files
You can drag text files directly onto the chat panel to import existing documentation. reads the file, extracts the relevant knowledge, and creates wiki pages and rules from the imported content.
Supported formats include `.md`, `.mdx`, `.txt`, `.yaml`, `.json`, `.py`, `.ts`, `.js`, and other common text-based formats (up to 1 MB per file).
**Example use cases:**
* Drag your team's `CONTRIBUTING.md` to import coding standards
* Drop an architecture decision record (ADR) to capture design choices
* Import a `styleguide.md` to encode formatting preferences
### From a URL or Repo Path
In the chat, you can also reference external sources:
```
Please read the coding standards from our wiki at
https://internal-wiki.example.com/coding-standards
and create rules from them.
```
Or point to a file in your repository:
```
Read the patterns in src/shared/base-repository.ts
and create a wiki page documenting the repository pattern we use.
```
## Editing Wiki Pages
Wiki pages capture architecture, patterns, and project-specific context. Update them through the chat.
Right-click any item in the tree (wiki, rule, milestone, Project Spec, etc.) and select **Add to context** to attach it to the chat. You can also select text in the content panel and use the same **Add to context** action. Then describe the change you want:
```
Add a section about connection pooling.
We use a max of 20 connections per service instance.
```
```
Create a new wiki page about our error handling strategy.
All domain errors should extend AppError. HTTP errors are mapped
in the error middleware, not in individual handlers.
```
On Project Spec, milestones, wikis, and rules you can also leave **artifact comments** on selected text — useful for team review before asking chat to apply changes.
### When to Add Wiki Pages
Add wiki pages when you have knowledge that applies broadly but isn't a hard rule:
* **Architecture decisions** — "We chose event sourcing for the order service because..."
* **Integration notes** — "The payment gateway expects ISO 8601 dates with timezone"
* **Migration context** — "The legacy `UserManager` class maps to three separate services in the new architecture"
* **Patterns** — "All API responses follow the envelope pattern: `{ data, meta, errors }`"
## Editing Rules
Rules are hard constraints that agents follow in every milestone. Unlike wiki pages (which provide context), rules are treated as requirements.
**Create and update rules through chat:**
```
Create a rule: all Python files must use absolute imports.
No relative imports allowed except in __init__.py files.
```
**Manage rules in the UI:** select a rule in the tree to edit its content, change status (**Draft** → **Published** → **Archived**), or delete it. New rules start as **Draft** until you publish them — only **Published** rules apply to agent execution.
To update an existing rule via chat, right-click it (or select text) and **Add to context**, then describe the change:
```
Update this rule to also require that every new endpoint
has at least one integration test.
```
### Rules vs. Wiki Pages
| | Rules | Wiki Pages |
| ------------------ | ------------------------------------------------------ | --------------------------------------------------------- |
| **Agent behavior** | Treated as requirements — agents must follow them | Treated as context — agents use them to inform decisions |
| **Scope** | Apply to every milestone (when published) | Referenced when relevant |
| **Best for** | Coding standards, library mandates, naming conventions | Architecture docs, design decisions, integration notes |
| **Example** | "Use pytest for all tests. No unittest." | "The authentication service uses JWT with RS256 signing." |
Use rules when you want to **enforce** something. Use wiki pages when you want to **inform** agents.
## Editing Milestones
You can review milestone descriptions in Project Knowledge. To adjust scope, add requirements, or change descriptions, use [Editing Milestones](/customization/editing-milestones) from the milestone review flow.
You can also ask to restructure milestones through chat. For example, to merge two milestones:
```
Merge Milestone 3 ("Migrate user authentication") and
Milestone 4 ("Migrate session management") into a single milestone.
They're tightly coupled and should be done together.
```
### Locked Milestones
Milestone plans in Project Knowledge are view-only once execution has started. A milestone is locked when its status is anything other than **Not Started** — including in progress, pending review, failed, blocked, or merged.
If you need to adjust a milestone that's already executing, wait for the current execution to complete (or merge it), then make your changes before re-running.
For small, recurring adjustments across milestones, add a [Rule](#editing-rules) instead of editing each milestone individually. Published rules apply to all milestones automatically.
## Updating the Project Spec
The **Project Spec** is the top-level document that defines your migration's goals, scope, and approach. Ask in chat to refine the migration direction; substantial changes may also go through your Project Spec approval flow (see [Reviewing the Project Spec](/setup/reviewing-project-spec)).
Changes to the Project Spec can affect how agents approach future milestones, so be deliberate about what you request.
## Viewing Changes
When modifies knowledge during an agent execution (for example, an agent discovers a pattern and writes a wiki page), you can see exactly what changed.
Click **Show changes** (the diff icon) in the Project Knowledge toolbar to toggle an inline diff view:
* **Green** highlights show added content
* **Red** highlights with strikethrough show removed content
* A summary shows the total lines added and removed
* Modified items are marked with a status dot in the tree navigation
This makes it easy to review what agents learned and wrote back during execution. The button is disabled when there are no pending changes to show.
## How Knowledge Stays in Sync
Project knowledge stays aligned with running work as agents read and write it, and as you add or update context through the chat. When you ask for changes while an agent is running, incorporates them so agents can pick up new rules and wiki context in subsequent steps.
## Examples
### Setting Up a New Project's Knowledge
When you start a migration, front-load project knowledge with what you know:
```
Our project follows clean architecture. The layers are:
- Domain (entities, value objects, repository interfaces)
- Application (use cases, DTOs, application services)
- Infrastructure (database repos, external API clients, message handlers)
- Presentation (controllers, middleware, request/response models)
Dependencies point inward. Infrastructure depends on Domain,
never the reverse. Use dependency injection everywhere.
```
creates wiki pages for the architecture and rules for the dependency direction constraint.
### Correcting Agent Behavior
After reviewing a PR, you notice agents are using `console.log` for debugging:
```
Create a rule: never use console.log in production code.
Use the logger service from src/shared/logger.ts for all logging.
Debug logs should use logger.debug(), errors should use logger.error()
with the full error object.
```
All future milestones follow this rule once you publish it.
### Importing Team Standards
Your team has a `docs/coding-standards.md` in the repo:
1. Drag the file onto the Knowledge chat panel
2. reads it and creates wiki pages and draft rules from the content
3. Review the created entries in the tree navigation
4. Publish rules you want enforced, and ask the chat to adjust any entries that need refinement
### Chat History and Retention
Chat conversations are saved by default so you can come back to a session and see what was discussed and decided.
If your organization would rather they were not retained on our servers, an administrator can turn this off under **Project Settings → Chat History** by clearing **Save chat history**. There is also a purge action that permanently deletes all saved chat history for the project.
Two things to weigh before turning it off:
* Conversations cannot be recovered if the workspace is lost.
* Workspaces are recycled after **7 days of inactivity**, so without persistence, history from an idle project goes with it.
While persistence is off, shows a standing warning on the project so nobody is surprised by missing history later.
### Adding Context Mid-Migration
At Milestone 4, you realize agents don't know about a critical integration:
```
The user service calls the billing service over gRPC.
The proto files are in shared/proto/billing.proto.
When migrating user-related code, preserve all billing
service calls and use the generated Python client from
shared/generated/billing_pb2_grpc.py.
```
Milestones 5 onwards now have this context.
## Best Practices
### Let the Chat Do the Structuring
Don't worry about formatting your input perfectly. Describe what you want in natural language and structures it into the right wiki pages and rules. A rough paragraph of context works better than trying to manually create the "right" wiki page.
### Review Agent-Created Knowledge
After each milestone, open Project Knowledge and check for new wiki entries and draft rules. Agents write back what they learned. If something is inaccurate, ask the chat to correct or remove it before the next milestone picks it up.
### Use Rules for Enforcement, Wikis for Context
If you find yourself writing a wiki page that says "always do X" — that's a rule. Move it there so agents treat it as a hard requirement, not optional context.
***
## Related Docs
Reference for lifecycle scripts, env vars, validation status, and re-validation
How High vs Low/Medium affects Project Setup onboarding
Import organizational knowledge from existing projects
Approve the Project Spec using Project Knowledge and chat
Deep dive into writing effective rules with examples
How to adjust milestone scope and descriptions
Morph terminology and mental model
# Creating Rules
Source: https://docs.modelcode.ai/customization/rules
Encode your team standards and preferences into every milestone
Rules are custom instructions that apply across your entire migration. They let you encode specific requirements, coding standards, or preferences that should follow in every milestone.
## Why Create Rules
### You Know Your Standards
Every team has conventions. Maybe you:
* Always use a specific logging library
* Follow particular naming conventions
* Have standard patterns for error handling
* Require certain testing approaches
Rules let you capture this knowledge so respects it throughout your migration.
### Consistent Output
Without rules, makes reasonable choices-but they might not be *your* choices. Rules ensure:
* All generated code follows your patterns
* The same standard applies across every milestone
* You don't have to fix the same issue repeatedly
### Prevent Repeated Mistakes
If you review a milestone PR and notice something wrong, ask: "Will this happen again?" If yes, create a rule. The next milestone-and all after-will follow it.
## When to Create Rules
Create a rule when you:
* **Know exactly what you want** - You have a specific requirement, not a vague preference
* **See a pattern emerging** - The same issue appears across milestones
* **Have company standards** - Your team has documented conventions
* **Need specific library usage** - You want to use particular dependencies
## Rule Examples
### Coding Conventions
```
When translating to Python, follow these conventions:
- Use snake_case for function and variable names
- Use PascalCase for class names
- Maximum line length of 88 characters (Black formatter style)
- Use f-strings instead of .format() or % formatting
```
### Library Preferences
```
For all database access in the destination code:
- Use SQLAlchemy 2.0 with async support
- Implement the repository pattern
- Create separate repository classes for each entity
- Never write raw SQL in service layers
```
### Testing Requirements
```
For all generated tests:
- Use pytest as the testing framework
- Follow the Arrange-Act-Assert pattern
- Each test file should mirror the source file structure
- Use factory_boy for test fixtures
- Aim for 80% code coverage on new code
```
### Error Handling
```
For error handling in the destination code:
- Create custom exception classes for domain errors
- Use try-except blocks only for operations that can fail
- Log all exceptions before re-raising
- Never swallow exceptions silently
```
### Architecture Patterns
```
When migrating the service layer:
- Implement dependency injection for all services
- Services should depend on abstractions, not implementations
- Keep services stateless
- Use constructor injection, not method injection
```
### Specific Avoidances
```
Do NOT use the following in destination code:
- Global variables or module-level state
- print() for logging (use the logging module)
- Wildcard imports (from x import *)
- Mutable default arguments in functions
```
## Creating a Rule
1. In your project, open **Project Knowledge** and find the **Rules** section in the tree
2. Click the **+** button — the Knowledge drawer opens in rule-edit mode with a default title (e.g., "Rule 1")
3. Click the title to edit it — give it a short, descriptive name (e.g., "Python naming conventions")
4. Fill in **Description** (`Apply this rule when...`) — when this rule applies. A description is required to save.
5. Write the rule body in the markdown editor below — the specific instructions
6. (Optional) Toggle the **Active** checkbox off to save as a draft instead of publishing immediately
7. Click **Create Rule**
When editing an existing rule, the same button reads **Save Changes**.
### Writing Effective Rules
**Be Specific**
Instead of: "Write clean code"
Write: "Functions should do one thing. If a function exceeds 20 lines, consider splitting it."
**Be Actionable**
Instead of: "Use good error handling"
Write: "Wrap external API calls in try-except blocks. Log the error with full context. Re-raise as a custom DomainException."
**Provide Examples When Helpful**
```
When converting callbacks to async/await:
INSTEAD OF:
getData(function(result) {
process(result);
});
USE:
const result = await getData();
process(result);
```
## How Rules Are Applied
Rules are included in the context for every task in every milestone. When generates code:
1. It reads all active rules for your project
2. It applies them alongside the milestone-specific instructions
3. Generated code reflects both the milestone goal and your rules
## Managing Rules
### Viewing Rules
Click on any rule in the Rules section to view its full content.
### Editing Rules
1. Click on a rule
2. Modify the title, description, or content
3. Save your changes
Edited rules apply to future milestones. Already-completed milestones aren't affected.
### Archiving Rules
If you no longer need a rule but want to keep it for reference, you can archive it by changing its status to **Archived** from the status dropdown in the **Project Knowledge** toolbar. Archived rules are inactive and do not apply to future milestones.
### Deleting Rules
When a rule is open in the editor, click the **Delete** button (trash icon) in the toolbar and confirm in the dialog that opens.
Deleted rules no longer apply to future milestones.
## Best Practices
### Start Focused
Don't try to create 20 rules upfront. Start with:
1. Your most important coding conventions
2. Critical library or framework requirements
3. Any non-negotiable patterns
Add more rules as you review milestones and notice gaps.
### Review Rule Effectiveness
After a few milestones, check:
* Are the rules being followed?
* Are they too vague (and being ignored)?
* Are they too strict (and causing issues)?
Adjust as needed.
### Keep Rules Maintainable
Many specific rules are better than one giant rule. Separate concerns:
* One rule for naming conventions
* One rule for error handling
* One rule for testing patterns
This makes rules easier to update and understand.
## Rules vs. Project Spec
| Project Spec | Rules |
| -------------------------------------- | -------------------------------- |
| Define the overall migration goal | Define recurring standards |
| Approved once, apply to entire project | Can be added/modified anytime |
| Describe *what* to migrate | Describe *how* to write code |
| Set at project start | Added as you learn what you need |
Both work together. The Project Spec sets the direction. Rules fine-tune the execution.
# Organizational Knowledge
Source: https://docs.modelcode.ai/customization/shared-knowledge
A centralized view of all organizational knowledge, with the ability to import into new projects
As projects are set up — lifecycle scripts, dependencies, acceptance criteria, instructions — automatically makes that knowledge available across your organization. The **Organizational Knowledge** page provides a single place to see everything your organization has built, and when creating a new project you can import from it to skip onboarding.
## How It Works
automatically tags project artifacts (lifecycle scripts, dependencies, acceptance criteria, instructions, project configuration, and wikis) with their associated repositories. This makes them discoverable as organizational knowledge without any manual step.
The following artifact types are tracked:
| Artifact | What's included |
| ------------------------- | ----------------------------------------------------------------------------------------- |
| **Lifecycle scripts** | Install, build, run, healthcheck, and test scripts with their execution order |
| **Dependencies** | The project's dependency manifest |
| **Acceptance criteria** | Origin-side acceptance criteria with their prompts and script references |
| **Instructions** | Published instructions with their content and tags |
| **Project configuration** | Build configuration settings — shown for reference only, never applied to another project |
| **Wikis** | Project wiki pages |
## Browsing Organizational Knowledge
The **Organizational Knowledge** page (accessible via the **Knowledge** tab in the sidebar, visible to administrators) is the central hub for all knowledge across your organization. Use it to understand what configuration exists, review how other projects are set up, and identify reusable patterns.
The page shows a card for each knowledge group. Each card displays:
* The repository handles the knowledge applies to
* Which project it originated from
* Artifact type buttons with counts you can expand to read the full content
### Reading Artifact Content
Click any artifact type button on a card to expand and read its content. The content renders in the same format used in the project's own knowledge views.
When an artifact type has multiple items (for example, 2 instructions), each item is numbered (e.g., "Instructions 1/2", "Instructions 2/2") with a divider between them.
### Searching and Filtering
Use the **search bar** to find knowledge by repository name. Matching text is highlighted in the results.
Use the **Filter by repo** dropdown to narrow the list to cards containing specific repositories. The filter supports two modes:
| Mode | Behavior |
| ---------------- | --------------------------------------------------------------------------------- |
| **Contains any** | Shows cards where at least one selected repository appears |
| **Contains all** | Shows only cards where every selected repository appears together in the same set |
Use the **Filter by project** dropdown to narrow the list to knowledge originating from specific projects. Multiple projects can be selected.
## Importing During Project Creation
When you create a new project and select repositories, automatically checks for available organizational knowledge. You see one of two states in the **Organizational Knowledge** section of the create project form:
| State | What you see |
| ----------------- | ------------------------------------------------------------------------------ |
| **Available** | "Skipped — starting fresh" with a **Manage** button to browse and select items |
| **Not available** | A message confirming no organizational knowledge exists |
### Selecting Items to Import
Click **Manage** to open the knowledge transfer drawer. It shows the **instructions** and **wikis** available across your organization — you are not limited to projects that share repositories with this one. The items most relevant to your project are marked **Recommended**, so the useful knowledge is easy to find without the rest being hidden from you.
**Filtering and searching.** Use the category tabs at the top to filter by artifact type (All, Recommended, Instructions, Wikis) or type into the search bar to find items by name. When a search is active, matching text is highlighted in the results.
**Selecting items.** Each item has a checkbox. Click an item row or its checkbox to select it. No items are pre-selected by default.
**Previewing content.** Click the **Preview** button on any item to open its full content in a side panel next to the list, rendered in the same format as the project's own knowledge views.
**Importing.** The footer shows how many items are selected. Click **Import** to proceed. If no items are selected, click **Skip for now** to start fresh.
Once you close the drawer, the create project form updates to show how many items are selected (for example, "3 items selected"). Click **Manage** again to reopen the drawer and adjust your selection.
### After Import
When you create the project, selected items are copied into it. Onboarding stages covered by the imported configuration are marked as complete, and you proceed directly to later stages.
**Project configuration is the exception.** It is tracked, listed and browseable like any other artifact, but importing it writes nothing into the new project. The settings it carries — the project's platform, and whether it runs on Modelcode Hosted or Self hosted — are chosen once at the Build Environment step and are [permanent afterwards](/setup/build-environment/switching-environment), so they have to be a decision someone makes for that project rather than something an import brings along. Use it to see how a comparable project is set up, then make the same choice deliberately.
After import, the new project owns its own copy of the configuration. Changes in the new project do not affect the source, and changes in the source project do not affect projects that already imported from it.
## Recommendations From Your Approved Spec
Once your Project Spec is approved, reads it and looks through your organization's knowledge for anything worth reusing on this project — going on what the migration actually intends to do, not only on which repositories match.
This appears as a step in your project's onboarding checklist. Relevant items are marked **Recommended**, and you can hover the tag to see why thinks an item applies to your project. You choose what to bring in; nothing is imported without you.
This is where a second migration gets cheaper than the first: the lifecycle knowledge, conventions, and corrections earned on earlier projects arrive at the start rather than being rediscovered.
## Importing During the Migration
You can also import organizational knowledge into an existing project. On the project page, click **Import Knowledge** in the sidebar to open the import drawer.
Mid-project import is available only when no execution is currently running on the project.
The mid-project import drawer shows a different set of artifact types than the creation-time drawer:
| Context | What's shown |
| ---------------------- | ------------------------------------------------------------------------------------------------ |
| **Project creation** | Instructions and wikis from across your organization, with matching items marked **Recommended** |
| **Mid-project import** | Instructions, wikis, and acceptance criteria |
During mid-project import, items are marked with a green **Recommended** tag based on how relevant they are to the project's approved spec. Hover the tag to see why the item is relevant. Any displayed item can be imported regardless of its recommendation status.
**Collision handling.** When importing into an existing project, items that share the same name as an existing wiki or instruction in the project are flagged as collisions. For each collision, you can choose to **replace** the existing item, **keep both**, or **skip** that item.
## Matching Rules
Organizational knowledge is available to all new projects in the tenant. Items are marked **recommended** based on how relevant they are to the project — its repositories and, once it exists, its approved spec.
During **project creation**, the drawer shows instructions and wikis, with the most relevant marked **Recommended**. During **mid-project import**, all non-environment items are shown, again with recommendations highlighted. In both cases you choose what to import — nothing is selected for you.
# Introduction
Source: https://docs.modelcode.ai/introduction
Automated code modernization for your repositories
automates the migration of codebases from one technology stack to another. Whether you're upgrading Python 2 to Python 3, translating Ada to C++, or migrating a legacy framework to a modern one, handles the heavy lifting.
## How It Works
connects to your repositories and modernizes them according to your goals. A project can include one or more repositories, each with a defined role in the migration. The process is designed to be transparent and controllable:
1. **You define the goal** — Describe what you want: "Translate from Ada to C++" or "Upgrade to Python 3.12"
2. **You set up the build environment** — Configure how your project builds, runs, and tests
3. ** understands your code** — We analyze your repositories and document their architecture
4. **You approve the plan** — When your Project Spec is ready, opens [**Project Knowledge**](/customization/project-knowledge) automatically the first time (the Roadmap drawer with your spec, chat, and related context) so you can review and approve it using chat before any code is generated
5. ** executes in milestones** — The migration happens in logical chunks, each delivered as a Pull Request for your review
6. **You control the merge** — Every change goes through your normal code review process
## Why This Approach
### You Stay in Control
Automated migrations can be risky. is designed so you never lose control:
* **Nothing changes without your approval** — The Project Spec must be explicitly approved before migration begins
* **Progressive delivery** — Changes come in milestones, not one massive PR
* **Standard GitHub workflow** — Every milestone produces a PR you can review, comment on, and merge like any other
### The AI Understands Context
Before generating any code, builds a comprehensive understanding of your repositories:
* What technologies and frameworks are in use
* How components connect to each other
* Architectural patterns and conventions
This context ensures the migrated code respects the intent and structure of your original application.
### Multi-Repository Support
Real-world modernizations often span multiple repositories. supports multi-repo projects where each repository has a defined role:
* **Modified** — An existing repository that will be transformed
* **New** — A new repository created as part of the migration
* **Reference Only** — A repository used for context but not modified
* **One-to-One Migration** — Direct migration from one repository to another
Each project has a [lifecycle configuration](/setup/build-environment/lifecycle-setup) — scripts, environment variables, and a lifecycle document that define how the application builds, runs, and tests. For both cloud projects and projects on a [V2 self-hosted daemon](/setup/build-environment/self-hosted-daemon), an agent works this out with you in chat during the **Project Setup** onboarding stage, then validates it end to end.
### Customizable to Your Standards
Every team has coding standards. lets you define **Rules** that encode your preferences:
* "Always use dependency injection for database connections"
* "Follow our naming convention for React components"
* "Use our internal logging library instead of console.log"
These rules apply across all milestones, ensuring consistent output that matches your team's expectations.
## What You Can Migrate
handles a wide range of modernization scenarios:
| Scenario | Examples |
| ------------------------------ | ------------------------------------- |
| **Language upgrades** | Python 2 → Python 3, Java 8 → Java 21 |
| **Language translations** | Ada → C++, COBOL → Java |
| **Framework migrations** | AngularJS → React, Express → FastAPI |
| **Architecture modernization** | Monolith → Microservices |
## Next Steps
Ready to start? Head to the [Quickstart](/quickstart) guide to create your first migration project.
# Adhoc Milestones
Source: https://docs.modelcode.ai/migration/adhoc-milestones
Add new work to your migration as a full milestone — planned, approved, and executed like any other
Sometimes you need work that was not part of the original roadmap — a missing feature you noticed during review, a follow-up refactor, or a one-off requirement that does not belong in an existing milestone. **Adhoc milestones** let you describe that work in plain language; turns it into a full milestone plan, and you run it through the same approve → implement → review → merge flow as every other milestone.
Adhoc milestones appear on the Roadmap under **Ad Hoc Work**, numbered as sub-milestones (for example **3.1** after milestone 3). They are not quick in-place task edits — they are real milestones with their own spec, tasks, validation, and pull request.
***
## When to Use an Adhoc Milestone
* **Scope that deserves its own milestone.** The work is more than a small fix — it needs planning, multiple tasks, or its own PR.
* **Work discovered mid-migration.** You spot a gap during PR review, testing, or demo prep that should ship before you move on.
* **One-off requirements outside the original spec.** You need something done now without re-running roadmap generation for the whole project.
* **At the end of the project, when Final Code Delivery is ready.** All standard milestones are merged and the final delivery PR is open — but you still need an ad hoc fix, refactor, or change before you ship. Create an adhoc milestone to handle that work through the normal milestone pipeline; Final Code Delivery waits until any open ad hoc / upstream milestone completes.
For smaller adjustments inside an *existing* milestone's scope, prefer [editing the milestone spec](/customization/editing-milestones) before approval, or [Code Review Chat](/migration/code-review-chat) to resolve issues on a milestone already in review.
For preferences that should apply across *future* milestones, add a [Rule](/customization/rules) instead.
Adhoc milestones are different from **Ad hoc Validation** and **Upstream Sync** — those are specialized off-sequence milestones for rerunning validation or merging upstream changes. This page covers **Ad hoc Milestone** only.
***
## Creating an Adhoc Milestone
1. Open the project **Roadmap**.
2. In the sidebar, find the **Ad Hoc Work** section.
3. Click **Ad hoc Milestone**.
4. In the drawer, describe your requirement in plain language — what you need, why, and any constraints that matter (files, APIs, test expectations, etc.).
Example requirement:
> Add rate limiting to the public API endpoints. Use a token-bucket per client IP, return HTTP 429 with a clear error body, and cover the happy path and limit-exceeded cases with tests.
5. Click **Create Ad hoc Milestone**.
creates a placeholder milestone (numbered **X.1**, anchored after the last standard milestone you have started) and runs **adhoc milestone planning** in the background. While planning runs, the milestone card shows **Generating plan…**
When planning finishes:
1. Open the milestone on the Roadmap or in **Project Knowledge**.
2. Review the generated milestone spec — title, description, deliverables, and task breakdown — the same way you would for a standard milestone.
3. Edit the spec if needed, then **approve** it.
4. Start implementation and follow the normal [milestone lifecycle](/migration/milestones-and-tasks).
If planning fails, the milestone card shows a failure state with **Retry**. Fix anything blocking the agent (for example daemon connectivity), then retry planning in place — you do not need to re-enter the requirement.
***
## How Adhoc Milestones Behave
Once the plan is ready, an adhoc milestone behaves like any other milestone:
| Stage | What happens |
| ------------------ | -------------------------------------------------------------------------------------------------------- |
| **Planning** | Agent generates a milestone spec from your requirement (automatic for adhoc milestones). |
| **Approval** | You review and approve the spec in Project Knowledge before implementation starts. |
| **Implementation** | Agent executes tasks, commits code, and opens a milestone pull request. |
| **Review & tests** | Automated review and functional tests run according to your [validation level](/setup/validation-level). |
| **Merge** | You triage review issues, merge the PR, and the milestone completes. |
Adhoc milestones participate in the same dependency and sequencing rules as standard milestones. Other milestones that depend on this work stay blocked until the adhoc milestone is merged.
***
## Planning in Parallel, Running One at a Time
Creating an adhoc milestone only **plans** it — nothing runs until you start it. So you can create as many as you like, whenever you like, including while another adhoc milestone is still open or while a standard milestone is in progress. Each new one lands on the Roadmap as the next sub-milestone (**3.1**, then **3.2**, and so on) and waits for you.
Execution is what is serialized. A queued milestone shows as **Pending** with no start action until every earlier off-sequence milestone at the same anchor has finished, and only one off-sequence milestone. You always start each one yourself; a queued milestone never begins on its own.
**Ad hoc Validation** and **Upstream Sync** work differently: those two actions *are* disabled while other milestone is running or any off-sequence milestone is still open.
### Adhoc milestones proposed in chat
[Project Knowledge](/customization/project-knowledge) and [Code Review Chat](/migration/code-review-chat) can also write an adhoc milestone plan for you when you ask for work that is too large for the conversation at hand. The agent writes the plan, and the milestone appears on the Roadmap when the turn ends — queued exactly like one you created from the sidebar.
***
## When You Can (and Cannot) Create One
### You can create an adhoc milestone when
* The project has an active project spec (normal after onboarding).
* Your build environment is ready to accept work — on [Modelcode Hosted](/setup/build-environment/modelcode-hosted) this is automatic; on a [Self-hosted Daemon](/setup/build-environment/self-hosted-daemon), your project's pool needs at least one machine online.
### You cannot create one when
| Blocker | What to do |
| ------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| **No machine available in the pool** (self-hosted only) | Start or reconnect a machine in the project's pool. See [Pool and Daemon Status](/setup/build-environment/self-hosted-daemon#pool-and-daemon-status). |
***
## Tips for Effective Requirements
* **Be specific.** Name endpoints, files, libraries, or behaviors you care about. "Add rate limiting to `/api/v1/*`" beats "improve the API."
* **State what done looks like.** Include test expectations, status codes, or acceptance criteria the agent should satisfy.
* **Right-size the ask.** One adhoc milestone should cover one coherent piece of work. If the requirement spans multiple unrelated features, split it into separate adhoc milestones or update the [roadmap](/migration/roadmap) instead.
* **Review the generated plan before approving.** Planning aligns the work with your project spec and current migration state — treat the spec like any other milestone and edit it before you approve.
***
## Related Docs
The full milestone lifecycle from approval through merge
How milestones are ordered and unlocked
Adjust a planned milestone before approving it
Resolve review issues on a milestone already in progress
Ad hoc Validation vs. adhoc milestones
Encode recurring preferences across milestones
# Code Review Chat
Source: https://docs.modelcode.ai/migration/code-review-chat
Interactively triage milestone review issues, chat with Morph, and re-run reviews
**Code Review** is where users can review the work has done on a milestone. You open it from the **Roadmap**: once a milestone is complete, click **Code Review** to open this drawer.
## What's Inside
* **Interactive hub for milestone review issues.** Every review issue surfaced for the milestone lives in **Code Review**, with filters for status, severity, tags, and resolution, and the option to group issues by severity, status, source, size, or tags.
* **Chat with Morph to take action.** Ask Morph to resolve open issues, create new ones, re-run the review, or add your own review criteria — all from the chat panel on the right.
* **One view across every repo in the milestone.** The **Code Review** drawer combines issues across all repositories in the milestone. When you want to inspect the underlying diff, use **View Pull Requests** to open the individual PRs externally.
* **Effort estimates at a glance.** Issues the review agent has sized carry a T-shirt-size badge (XS–XL) on the card; hover it to see the estimated effort. Larger estimates use warmer colors.
* **Provide a secret when asked.** If the agent needs a credential to make or verify a change (for example, an API key to run a test), it asks with a **Provide Secret** card rather than in the chat box. The value is encrypted immediately and is never shown to the agent or written into the transcript. See [Providing secrets](/setup/build-environment/lifecycle-setup#providing-secrets).
## Common Actions
* **Resolve an open issue** — ask Morph to fix it, or mark it resolved after a manual change.
* **Create a new issue** — flag something the review missed. You can even drag-and-drop external documents to import issues in bulk.
* **Re-run the review** — use the **Re-run review** button after code changes or new criteria.
* **Tag an issue** — click **Tags** on any issue card to open the tag picker. Toggle tags from your project's catalog on or off, or type a new name and choose **Create "\"** to add it to the catalog and apply it in one step. Tags show as chips on the issue row and work with the **tags** filter and grouping in the toolbar.
* **Run the frontend tests** — on projects with a frontend, ask the chat to run or re-run the milestone's frontend (Playwright) test suite — for example, after it fixes a UI bug. The run takes a few minutes to build and boot the app; when it finishes, pass/fail results and screenshots refresh in the **Validation** tab and the milestone's [Functional Testing](/migration/functional-testing) view — no reload needed.
***
## The Validation tab
Alongside the issues list, the drawer's **Validation** tab shows this review's own test results, scoped to the exact run under review — API/CLI, UI Tests (Playwright), QA Agent (agent browsing captures), and Lifecycle. Each row has a **Discuss** action that pulls that result into the chat as context. See the [Validation Hub](/migration/functional-testing) for the project-wide view.
***
## Collaboration
Multiple team members can review the same milestone simultaneously. Each reviewer gets their own independent **review chat session**, so conversations and issue triaging don't collide.
### How it works
* When you open **Code Review** for a milestone, creates (or resumes) a review session scoped to your user. Your teammate opening the same milestone gets their own session.
* Each session has its own chat history, issue resolutions, and context. You can work through different issues at your own pace without blocking each other.
* **Proactive peer sync:** When one reviewer resolves an issue or the agent applies a fix, propagates the change to other active reviewers' workspaces so everyone sees the latest code state.
### Session locking
Only one user can actively chat with on a given milestone at a time. If a teammate is currently in an active chat session, you'll see a message indicating who is using it. Once they finish (or their session times out after inactivity), the session unlocks and you can start yours.
This ensures the agent isn't receiving conflicting instructions from multiple users simultaneously while still allowing parallel *review* of issues and code.
Coordinate with your team on who is triaging which issues. Each reviewer can focus on different parts of the milestone — one person on backend logic, another on test coverage — and keeps the workspace in sync.
***
## Starting Over
Use **New chat** (or **Start over**) in the chat panel to reset your review session. This clears the current chat history and creates a fresh session — useful when you want to re-approach the review from scratch or after significant code changes. The review issues themselves are not deleted; only the chat conversation resets.
***
## Pool Capacity
Code Review chat is **exempt** from the [daemon pool](/setup/build-environment/self-hosted-daemon#pool-capacity) execution capacity gate. You can open a review chat session even when all workers in the pool are busy with milestone or ad-hoc executions.
However, actions that trigger non-chat work — such as **Re-run review** or approving a milestone from within the review — are still subject to pool capacity. If all workers are busy, those actions are blocked until a worker frees up.
***
## Final Code Delivery
When all milestones in a project are complete, surfaces a **Final Code Delivery** review. This is a separate review surface that works on the **project feature branch** rather than an individual milestone branch. All milestone work is bundled into one pull request per repository, and any change you make in this chat shows up in those PRs right away.
**What you can do in Final Code Delivery:**
* Get a walkthrough of what changed across the whole modernization
* Request a last-mile change (for example, updating the README to match the new build command)
* Ask why a service still calls a legacy endpoint
* Drag and drop a list of issues to be fixed
Use this chat for small, last-mile fixes. Larger refactors should go through an [ad-hoc milestone](/migration/adhoc-milestones) so they get a proper plan, validation, and review.
**Merging:** Final Code Delivery PRs must be merged on the **external PR page** (GitHub, GitLab, or Azure DevOps) — there is no in-app merge for final delivery.
***
## Rebase After Sibling Merge
If you open Code Review for a milestone and see a **Rebase Required** state, a sibling milestone was merged and this milestone's branch needs to incorporate those changes before it can proceed. See [Milestone Shows "Rebase Required"](/support/troubleshooting#milestone-shows-rebase-required) for resolution steps.
### Rebase Report
After a rebase completes, a **Rebase Report** tab appears in Code Review with a summary of what was brought in from the merged sibling milestone and how it was reconciled with this milestone's work.
It is worth a look before you merge. A rebase is the one point where code you already reviewed can change underneath you, and the report is where you see what moved — rather than inferring it from the diff.
The report is also given to the review agent as context, so you can ask about it directly in chat.
# Validation Hub
Source: https://docs.modelcode.ai/migration/functional-testing
Verify that migrated code behaves identically to the original with built-in functional tests and lifecycle validation
In large-scale migrations, syntactically correct code is not enough — static code analysis alone cannot verify that a migrated application behaves identically to the original. An API endpoint that returns a different status code, a CLI command that produces different output, or a UI that renders incorrectly can break downstream systems. Proving functional equivalence requires **runtime information**: actually executing both the origin and target applications and comparing their real outputs.
addresses this with **built-in functional testing**. As part of the migration process, Morph agents automatically generate, run, and verify functional tests that exercise both applications at runtime and compare their behavior side by side. No manual test authoring required. Results — together with the outcome of each build/run **lifecycle** script — are surfaced project-wide in the **Validation Hub**.
Functional testing works with **multi-repo projects** — each repository's tests are tracked and reported independently.
***
## How It Works
Functional tests are woven into the migration lifecycle — they are not a separate step you run after the fact. Here is how they fit in:
The [roadmap](/migration/roadmap) is established, defining the ordered set of [milestones](/migration/milestones-and-tasks) for your migration.
Morph dispatches testing agents for each milestone. **Backend testing agents** explore the source code, run the application, and record expected behavior for APIs and CLIs. **Frontend testing agents** generate Playwright scripts that exercise specific user flows with deterministic assertions. **User simulation agents** freely browse the application and document key moments as screenshots and videos. This ensures tests capture production-realistic details — bootstrap sequences, authentication, headers, visual layout, and more.
During [milestone execution](/migration/milestones-and-tasks#the-milestone-lifecycle), Morph agents run your migrated code and actively verify that functional tests pass as part of the implementation loop. Results appear in each milestone's test summary and in the project-level **Validation Hub**.
After execution completes, all tests are run against the PR branch. Results are reported in the UI so you can verify behavioral equivalence before merging.
### What Makes These Tests Different
| Aspect | Traditional test suites | Morph functional tests |
| -------------- | -------------------------------------- | --------------------------------------------------- |
| **Authoring** | Written manually by engineers | Auto-generated by agents exploring source code |
| **Basis** | Specification or developer assumptions | Observed *real* behavior of the running application |
| **Scope** | Varies by team discipline | Systematically covers every discovered entry point |
| **Comparison** | Pass/fail against assertions | Side-by-side origin vs. target response comparison |
| **Visual** | Not covered | Playwright tests + agentic browsing sessions |
### Supported Application Types
Morph functional testing covers four categories, grouped in the Validation Hub as **API/CLI** and **UI** (itself split into **Tests** and **QA Agent**):
| Type | Entry point | Input | Output compared |
| ----------------- | ---------------------------------------- | --------------------------------------------- | --------------------------------------------------- |
| **API** | Endpoint (e.g., `/add`, `/health`) | HTTP method, headers, request body | Status code + response body |
| **CLI** | Command or subcommand (e.g., `calc add`) | Arguments, flags, stdin | Exit code + stdout/stderr |
| **UI — Tests** | Page or user flow | Scripted browser interactions (clicks, input) | Pass/fail status, screenshots, video on failure |
| **UI — QA Agent** | Full application session | Agent-driven exploration | Screenshots and video of key moments (no pass/fail) |
***
## The Validation Hub
The Validation Hub is the project-level dashboard accessible from the sidebar. It organizes all test and lifecycle results across three tabs: **API/CLI** for backend tests, **UI** for frontend tests (scripted and agent-driven), and **Lifecycle** for the install/build/run/test scripts executed to stand up each application. Only tabs with results are shown.
The Hub is available at every [validation level](/setup/validation-level), including **Low**. At Low there are no functional tests to report, but your install and build scripts still run, so the **Lifecycle** tab tells you whether your application builds cleanly.
### API/CLI Tab
The API/CLI tab shows backend functional test results — API endpoint responses and CLI command outputs compared between origin and target.
#### Sidebar Tree
The left sidebar organizes tests in a hierarchy:
1. **Repository** — Each repo in the project is a collapsible group
2. **Entity** — Within each repo, tests are grouped by entry point, with a **passed/total** count (e.g., `8/8`):
* For APIs: `GET /health`, `POST /add`, etc.
* For CLIs: `$ checkWinner`, `$ findBestMove`, etc.
3. **Individual tests** — Each test case under its entity, showing pass/fail status, duration, a comparison icon if origin data is available, and — for failed tests — an external-link icon that jumps to the [linked review issue](#failed-tests-create-review-issues)
Use the **search bar** to filter tests by name, the **status filter** (All / Passed / Failed) to focus on what matters, and **filter by milestone** to see results from a specific execution.
#### Detail Panel
Selecting a test opens the detail panel on the right. The content adapts to the protocol type:
**For API tests:**
* **Endpoint** — HTTP method and path (e.g., `GET /system/info/public`)
* **Expected vs Actual Status** — Status codes with mismatch highlighting
* **Request Body** — The payload sent to both origin and target
* **Target Response** — Status code and response body from the migrated application
* **Origin Response** — Response body from the original application (when comparison data is available)
* **Match indicators** — Response Match / Response Mismatch tags with an optional diff view
* **Comparison Note** — An agent-written note explaining the comparison result — useful when origin and target differ for an expected reason (e.g., a version bump) rather than a real regression
* **Error** — On a failed test, the specific mismatch that was detected (e.g., `response body mismatch between origin and target`)
* **Failed test banner** — On a failed test, a banner across the top of the panel with a **Review Issue** button that jumps straight to the [auto-created review issue](#failed-tests-create-review-issues)
**For CLI tests:**
* **Command** — The full command invocation (e.g., `$ checkWinner [...]`)
* **Arguments** — The exact argument list passed to both origin and target
* **Expected vs Actual Exit Code** — With mismatch highlighting
* **Target stdout/stderr** — Output from the migrated application
* **Origin output** — Output from the original application (when comparison data is available)
* **Match indicators** — Output Match / Output Mismatch tags with diff view
See the Validation Hub screenshot above for an example CLI test detail panel (`checkWinner`). CLI tests share the same detail panel component as API tests, so a Comparison Note and failed-test banner appear there too when applicable.
### UI Tab
The UI tab groups both kinds of frontend testing under a pair of sub-tabs:
* **Tests** — scripted Playwright runs with deterministic pass/fail outcomes
* **QA Agent** — agentic browsing sessions with no concept of pass/fail
#### Tests
The **Tests** sub-tab shows Playwright test results — scripted browser tests with deterministic pass/fail outcomes and precise runtime information. These are traditional end-to-end tests that exercise specific user flows and assert expected behavior.
**Sidebar Tree** — Tests are organized by repository, then by spec file and describe block (e.g., `game.spec.ts > Tic-Tac-Toe Game`), then by individual test case, with a passed/total count on each group. Each test entry shows:
* **Pass/fail status** — Green checkmark for passing tests, red indicator for failures
* **Runtime** — How long each test took to execute (e.g., `290ms`, `2s`)
Use the **search bar** to filter tests by name, the **status filter** (All / Passed / Failed) to focus on what matters, and **filter by milestone** to see results from a specific execution.
**Detail Panel** — Selecting a test opens the detail panel on the right:
* **Test name and status** — The full test description with a pass/fail badge and duration
* **Artifacts** — Passing tests show a single screenshot of the final state
* **Video recording** — Failing tests additionally include a video recording of the full test run for debugging context
#### QA Agent
The **QA Agent** sub-tab shows agentic browsing sessions — an AI agent freely navigates the application and documents key moments as screenshots and videos. Unlike the Tests sub-tab, these sessions are exploratory and semantically meaningful, with no concept of pass or fail.
QA Agent sessions are typically used to increase trust and visibility into what the migration agent actually implemented and validated. They provide a human-reviewable walkthrough of the application's behavior.
**Sidebar Tree** — Sessions are organized by flow name (e.g., "AI Mode Toggle", "Two Player Turn Flow", "Tie Overlay"). Each flow entry shows:
* **Step count** — Number of documented moments in the session
**Step Viewer** — Selecting a flow opens the step viewer on the right:
* **Step navigation** — Arrow buttons or keyboard arrows to move between steps
* **Step label** — Description of what the agent observed at each moment (e.g., "AI mode enabled - title shows AI Mode text")
* **Screenshot** — A full-page screenshot captured at each documented moment
* **Video** — When available, a video recording of the agent's browsing session
### Lifecycle Tab
The Lifecycle tab shows the results of the [lifecycle scripts](/setup/build-environment/lifecycle-setup) — install, build, run, and test — that Morph executes to stand up each application. Use it to confirm the target app actually builds and runs before digging into functional test results; a lifecycle failure here explains a wave of downstream API/CLI or UI test failures.
#### Sidebar Tree
Scripts are grouped by milestone (e.g., "SvelteKit + Bun Full Migration"). Each script entry — `install`, `build`, `run`, `test` — shows:
* **Pass/fail status** — Green checkmark for a successful run, red indicator for failure
* **Duration** — How long the script took to run
Use the **status filter** (All / Passed / Failed) and **filter by milestone** to narrow the list.
#### Detail Panel
Selecting a script opens the detail panel on the right:
* **Status, duration, and exit code** — At-a-glance pass/fail summary
* **Script** — The exact shell commands that were run
* **stdout** — Full output captured from the run
* **Open in Project Knowledge** — Jumps to the underlying lifecycle document for that repo in [Project Knowledge](/customization/project-knowledge)
***
## Failed Tests Create Review Issues
Any functional test that fails automatically opens a review issue on the milestone's [Code Review](/migration/code-review-chat) drawer — tagged with `functional-test`, its protocol (e.g. `rest`), its category (e.g. `happy-path`), and `functional-testing` — so failures surface for triage without you having to go looking for them.
The failed test and its review issue are linked in both directions:
* **From the Validation Hub** — the failed test's detail panel shows a banner with a **Review Issue** button that jumps straight to the issue. In the sidebar tree, failed tests show an external-link icon as the same shortcut.
* **From the review issue** — the issue mirrors the test's data (request details, actual output, origin comparison) and can be discussed like any other review issue: open [Code Review Chat](/migration/code-review-chat) and ask Morph to fix it, or resolve it manually.
***
## Regression Across Milestones
From the second milestone onward, re-runs the functional tests accumulated from every previous milestone as a **regression suite**, after the current milestone's own tests.
This is what stops a long migration from drifting. Behavior proven in an early milestone keeps being proven as later work lands, rather than being taken on trust until someone notices in production.
Regression results appear alongside the milestone's own results. A regression failure is surfaced but does not block the current milestone — the right fix may belong in either milestone, and that is a judgement call rather than something to automate.
***
## Milestone Test Summary
Each milestone card on the [roadmap](/migration/roadmap) displays a test summary after execution completes. The summary shows per-repo results:
* **Backend tests** — Repository name with passed/total count and a comparison indicator
* **UI tests** — Repository name with passed/total count
* **QA Agent sessions** — Repository name with session count and step totals
This gives you a quick signal of migration health without navigating to the full Validation Hub.
***
## Tips
* **Review tests early.** As soon as tests are generated, skim them in the milestone test summary. If an entry point is missing, it may indicate the agent couldn't reach it — check your [lifecycle setup](/setup/build-environment/lifecycle-setup) configuration.
* **Check Lifecycle before API/CLI or UI.** If a milestone shows widespread test failures, check the Lifecycle tab first — a broken install/build/run step will fail everything downstream.
* **Use the Validation Hub for stakeholder updates.** The passed/total ratio and origin comparison counts are intuitive, non-technical measures of migration completeness.
* **Combine with rules.** If tests reveal a recurring pattern (e.g., missing headers, wrong status codes), create a [Rule](/customization/rules) so Morph handles it in future milestones.
* **Filter to failures.** On the API/CLI and UI tabs, use the **Failed** filter to focus your review on the tests that need attention.
* **Triage failures from the test itself.** A failed test's **Review Issue** button (or the sidebar's external-link icon) jumps straight into [Code Review](/migration/code-review-chat) with the failure details pre-loaded — no need to re-describe what broke.
***
## Related Docs
The milestone lifecycle, statuses, and task dependencies
High-level view of your migration plan
Best practices for reviewing milestone PRs
Triage review issues — including auto-created failed-test issues — with chat
Configure how your project builds and runs
# Milestones
Source: https://docs.modelcode.ai/migration/milestones-and-tasks
How milestones are reviewed, executed, automatically reviewed, shipped, and learned from
Milestones are the heart of your migration. Each one delivers a working increment that you review before proceeding, so changes stay small, reviewable, and safe. Within each milestone, the agent breaks the work into **tasks** and handles them automatically. After tasks finish, runs an **automated milestone review** and surfaces functional test and acceptance-criteria results before you merge. Once you merge, **learns from your changes** and updates project knowledge so the next milestone doesn't repeat the same mistakes.
For a high-level overview of the roadmap, see the [Roadmap](/migration/roadmap) page.
***
## The Milestone Lifecycle
Each milestone moves through these phases:
1. **Review the Milestone Spec** in Project Knowledge.
2. **Approve & Start** — from Project Knowledge, approve the spec and start the agent.
3. **Automated Review & Tests** — milestone review, functional testing, and acceptance criteria run automatically and surface in dedicated tabs.
4. **Triage the Review and Merge the Milestone** — open Code Review to triage issues with chat, then jump to the pull request(s) and merge.
5. **Milestone Learning** — after merge, learns from the PR review and your edits and updates project wikis and rules so future milestones avoid the same issues.
The expanded milestone card on the Roadmap exposes up to four tabs — **Tasks**, **Review**, **Tests**, and **Acceptance Criteria** — that appear as each phase becomes relevant.
***
### Step 1: Review the Milestone Spec
Before any code is generated, understand what the milestone will accomplish. Click a milestone on the Roadmap to expand it.
* If the milestone is **ready to start**, the **Next Step** alert offers **Review & Approve** — this opens **Project Knowledge** with the milestone spec selected.
* At any time, use the **Milestone Spec** button on the milestone action row to open the same view.
* If prerequisites are not met yet, the alert shows **View** instead — you can read the plan, but approval waits until earlier milestones merge.
Both entry points open the **Project Knowledge** drawer with the milestone selected in the tree — alongside your project spec, rules, wikis, and lifecycle setup.
In the drawer you can:
* **Read the full Milestone Spec** — scope, relevant files, design decisions, and risks the agent will follow.
* **Refine via Knowledge chat** — ask to clarify, expand, or adjust the spec. The agent updates the Milestone Spec in place.
* **Approve** — when you're satisfied, approve the milestone in the drawer to unlock **Approve & Start**.
For deeper guidance on editing the Milestone Spec — including `Validate following milestones` to make sure your edits don't break later milestones — see [Editing Milestones](/customization/editing-milestones). For the drawer itself, see [Project Knowledge](/customization/project-knowledge).
You don't have to change anything. If the plan looks good, approve it. But if something looks off, this is the cheapest place to fix it — much cheaper than fixing generated code later.
How to adjust the Milestone Spec before approving
The drawer where milestone specs, rules, and wikis live
***
### Step 2: Approve and Start
Approval and start happen in **Project Knowledge**, not on the Roadmap card itself. After you review the spec, click **Approve & Start** in the drawer toolbar.
Before the milestone runs, a **Start this milestone?** dialog shows what the work will cost in dollars and credits, and whether it stays inside your monthly allotment. Nothing starts until you approve it. See [Billing & Credits](/support/billing-and-credits#approving-a-milestones-cost) for what the figures mean.
Once approved, prepares a sandbox and the agent begins working autonomously: it plans tasks, works through them one by one, and commits code after each task.
To run a slow or flaky milestone faster, open the caret beside **Approve & Start** and choose **Start With Low Validation** — it implements and reviews this one milestone at the [Low validation level](/setup/validation-level#running-a-single-milestone-at-low) regardless of the project's setting. Run an ad-hoc validation after the PR merges to check the work at the project's level.
To run a slow or flaky milestone faster, open the caret beside **Approve & Start** and choose **Start With Low Validation** — it implements and reviews this one milestone at the [Low validation level](/setup/validation-level#running-a-single-milestone-at-low) regardless of the project's setting. Run an ad-hoc validation after the PR merges to check the work at the project's level.
A **Tasks** tab appears on the expanded milestone where you can watch progress in real time. Each task shows its ID (for example `M1-T001`), title, and status badge.
You don't need to babysit execution — the agent runs autonomously and progress is persisted. Open the milestone whenever you want to check on it; the **Tasks** tab keeps updating in the background.
***
### Step 3: Automated Review & Tests
After the agent finishes implementation, runs automated validation before the milestone is ready to merge. What runs depends on your project's [validation level](/setup/validation-level) — a project-wide setting that controls **whether Morph actually runs your application on the source side, the target side, both, or neither**:
| Validation level | Source (origin) app | Target app |
| ---------------- | ------------------------------- | ------------------------------------------------------- |
| **Low** | Not run | Not run — build and unit tests only |
| **Medium** | Not run | Run — full lifecycle (install, build, run, healthcheck) |
| **High** | Run — baseline captured upfront | Run — verified against the source baseline |
At **Low**, there is no functional testing or acceptance criteria — the **Acceptance Criteria** tab stays empty, and the **Tests** tab appears only after lifecycle commands (build and unit tests) have run. At **Medium**, validation exercises only the migrated app. At **High**, compares target behavior against what it observed on the source app, so regressions surface side by side.
The **Review** tab runs at every level — it inspects the agent's code changes regardless of whether the app is exercised at runtime.
Results surface as dedicated tabs on the expanded milestone card:
| Tab | When it appears | What it shows |
| ----------------------- | ------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Tasks** | As soon as planning produces tasks | The execution tasks the agent is working through |
| **Review** | Once the milestone review starts | The review tasks (the automated review pipeline) and a count of issues raised |
| **Tests** | When validation includes functional testing (**Medium**/**High**) or lifecycle commands have run | A summary of backend (API/CLI) and frontend (visual) functional test results for the milestone, with passed/total counts and origin-comparison counts where available |
| **Acceptance Criteria** | Once acceptance-criteria results exist | Pass/fail status for built-in and custom criteria tied to lifecycle scripts |
#### The Review tab
The **Review** tab tracks the milestone's automated review tasks — the pipeline that inspects the agent's output and raises issues against the migrated code. Once review tasks finish, the milestone exposes a **Code Review** button on its action row that opens the dedicated Review drawer (see Step 4). Failed functional tests [also raise issues here automatically](/migration/functional-testing#failed-tests-create-review-issues), linked back to the failing test for easy back-and-forth.
#### The Tests tab
The **Tests** tab appears when your validation level includes [functional testing](/migration/functional-testing) — **Medium** (target-only) or **High** (source baseline + target comparison) — or when lifecycle commands have run during milestone validation (for example install, build, run, or test scripts). It shows passed/total counts for backend (API/CLI) and frontend (visual) functional test runs where available, with origin-comparison indicators on **High**. From here you can jump into the full breakdown:
Verify behavior with auto-generated tests; the Tests tab is your milestone-scoped entry point
#### The Acceptance Criteria tab
The **Acceptance Criteria** tab appears when your validation level includes acceptance-criteria checks — **Medium** (target-only thresholds you author) or **High** (source baselines captured and compared on the target). It shows pass/fail status for built-in checks (build succeeds, tests pass) plus any custom criteria defined in [Project Knowledge](/customization/project-knowledge).
***
### Step 4: Triage the Review and Merge the Milestone
Once the automated review finishes and the pull request(s) are generated, the milestone moves to **Pending Code Review** (the UI label for all pending-review states, whether every task succeeded or some failed):
Everything from here happens through the **Code Review** drawer. Click **Code Review** on the milestone action row to open it — this is the single entry point for both triaging review issues and reaching the underlying pull requests (there's no separate "open PR" button on the milestone). The button stays disabled until a PR exists.
**Triage the review.** The Code Review drawer is an interactive hub for every issue raised on the milestone, with a chat panel for working through them. On this page you can:
* **Browse review issues** across every repository in the milestone, filtered by status and assignee.
* **Chat with ** to resolve issues, create new ones, add review criteria, or re-run the review against your latest changes.
* **Inspect the Milestone Spec and Project Spec** in side tabs without leaving the page.
Full walkthrough: filters, chat actions, importing external issues, and re-running the review
**Merge the milestone.** When the review looks good and tests pass, jump to the PRs from the same drawer:
1. Click **View Pull Requests** in the Code Review drawer header. A popover lists every PR in the milestone, each linking out to your SCM provider if you want to review or merge there.
2. Open each PR and review the code as you would any PR — leave comments, request changes, or push fixups.
3. When you're satisfied, click **Merge all PRs** in the Code Review drawer header to merge every open PR for the milestone in one step, without leaving . (Final Code Delivery is the exception — that PR must be merged on your SCM provider.)
After every PR in the milestone is merged, the milestone is complete and any dependent milestones are unlocked.
When a milestone PR is merged while sibling milestones are still in progress, automatically detects whether those sibling branches need to incorporate the newly merged code. If so, the affected milestones are flagged with a **Rebase required** alert — see [Rebase Required](#rebase-required) below.
Best practices for reviewing migration PRs
***
### Every milestone re-checks the ones before it
From the second milestone onward, also runs the functional tests accumulated from all previous milestones as a **regression suite**, after the current milestone's own tests.
This is what keeps a long migration honest: work that lands in milestone 8 cannot quietly break behavior proven in milestone 2 without you hearing about it. Regression results appear alongside the milestone's own results in the [Validation Hub](/migration/functional-testing).
A regression failure does not block the current milestone — it is surfaced for you to judge, since the right fix may belong in either milestone.
***
### Step 5: Milestone Learning
Merging the PR is the signal that the final state of the milestone is what you wanted — including every change *you* applied on top of the agent's output (review comments accepted, fixups you pushed, criteria you added, manual edits). treats that signal as a teaching moment.
As soon as a milestone PR is merged, a background **Milestone Learning** task runs automatically. An agent opens a sandbox with full access to the merged PR (review comments, inline feedback, the final diff, your follow-up commits) and looks for patterns worth keeping — corrections, conventions, architectural constraints, or anti-patterns that future milestones should respect.
Anything it finds gets written back to your project as updates to:
* **Wikis** — when the PR reveals new context about the codebase or how a subsystem actually works.
* **Rules** — when the PR enforces a convention, constraint, or fix-up pattern that should apply to future work (new rules start as **Draft** until you publish them).
Both update [Project Knowledge](/customization/project-knowledge) directly, so the next milestone's agent loads them automatically — no copy-pasting feedback, no repeating the same correction across milestones.
Milestone Learning runs **asynchronously and non-blocking**. You can start the next milestone right away — learning will keep running in the background and the updated wikis/rules will be in place by the time the next agent needs them.
You don't have to do anything to trigger this — merging the PR is enough. If you want to see what was learned, open [Project Knowledge](/customization/project-knowledge) after the next milestone starts and check **Rules** and **Wikis** for recent updates.
Where learned rules and wiki updates live
Conventions and constraints applied to every future milestone
***
## The Foundation Milestone
**Milestone 1** (the foundation milestone) includes an extra automated step before migration code lands: **target lifecycle discovery**. analyzes the target repo to determine how it should be installed, built, run, and tested. The discovered configuration is saved under **Target** in [Project Setup](/customization/project-knowledge) for you to review and edit.
When and how **origin** lifecycle is set up depends on your [validation level](/setup/validation-level):
| Validation level | Origin lifecycle | Target lifecycle |
| ---------------- | ------------------------------------------------------------------- | ---------------------------------------------- |
| **High** | Discovered during **Project Setup** onboarding (before Milestone 1) | Discovered during the **foundation milestone** |
| **Low / Medium** | Discovered automatically after your project environment is set up | Discovered during the **foundation milestone** |
If discovery cannot get the target application healthy automatically, the configuration is saved as **Draft — Needs Review** and a warning appears so you can fix it before proceeding.
***
## Milestone Statuses
As a milestone moves through its lifecycle, its status badge updates on the Roadmap. Here's what each one means in the UI:
| Status | Meaning |
| ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Blocked** | Either waiting for prerequisite milestones to merge (**Not Started** + **Blocked by** chips), or a hard failure state (agent crash, PR generation failure). Check the milestone alerts to tell which. |
| **Not Started** | All prerequisites satisfied. Ready to review and approve. No agent work has begun. |
| **In Progress** | The agent is actively working on tasks. |
| **Pending Code Review** | Implementation finished (with or without task failures). Review and/or PR generation is underway or complete — triage in Code Review. |
| **Merged** | You've merged the PR. Milestone complete. |
| **Completed** | The milestone is finished without a merge. Either it needed **no code changes**, so no pull request was opened, or its pull request was closed without being merged. Dependent milestones unlock the same as for **Merged**. |
Additional UI states you may see:
| UI element | Meaning |
| ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| **Locked** (milestone label) | Project setup is incomplete, or (on limited plans) the milestone is beyond your current access tier. Expand to see what's blocking it. |
| **Rebase required** | A sibling milestone merged and this branch needs to incorporate those changes before you can merge. |
| **Validating** | is re-validating a Milestone Spec edit you made in Project Knowledge. Wait before approving. |
A milestone reaches **Pending Code Review** whether or not every task succeeded. If some tasks failed, you'll see alerts on the milestone card and in the **Tasks** tab — so check there before assuming a clean run.
***
## Tasks
You don't need to interact with individual tasks — they execute automatically as part of the milestone. This section is here for when you want to follow along in detail.
### Task Statuses
| Status | Meaning |
| --------------- | ----------------------------------------------------------- |
| **Ready** | Waiting to be picked up. This is the default for new tasks. |
| **In Progress** | The agent is working on it. |
| **Completed** | Done. |
| **Failed** | The task ran into an error. |
| **Skipped** | A dependency failed, so this task was not run. |
| **Needs human** | The agent paused and needs input before it can continue. |
### Task Dependencies
Tasks can depend on other tasks. For example, "Implement authentication middleware" might need "Create project scaffolding" to finish first.
handles execution order automatically:
* A task stays in **Ready** until all of its dependencies have completed.
* Once a dependency finishes, tasks waiting on it become eligible to run.
* If a dependency fails, all tasks waiting on it are **skipped**. This prevents the agent from building on top of work that didn't succeed.
* Tasks with no dependencies can run in parallel (within the milestone's execution batch).
* If dependencies form a loop (Task A needs Task B, which needs Task A), catches this and stops with an error.
***
## Milestone Dependencies and Parallel Execution
Milestones can declare **dependencies** on other milestones. A milestone that depends on another will not unlock until the prerequisite is merged. When milestones are independent — no shared file or logical dependencies — they can execute in parallel.
### How it works
* analyzes file dependencies and logical ordering when generating the roadmap, and sets up a dependency graph automatically.
* **Independent milestones** (no shared dependencies) can be approved, started, and reviewed simultaneously — each runs in its own isolated branch.
* **Dependent milestones** stay **Not Started** with a **Blocked** badge and **Blocked by** chips until all listed prerequisites are merged.
* When a milestone is merged, any milestones that were waiting on it are automatically unlocked and become ready to start.
* On self-hosted deployments, parallel execution is bounded by your pool's capacity — starting another milestone is refused while every machine in the pool is occupied, and you can start it once one frees up.
### Milestone states related to dependencies
| What you see | Meaning |
| ---------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| **Blocked** badge + **Blocked by** chips | Waiting for one or more prerequisite milestones to merge. Cannot be approved and started yet. |
| **Not Started** (no Blocked badge) | All prerequisites satisfied. Review the spec and approve in Project Knowledge. |
| **Rebase required** alert | A sibling milestone was merged and this milestone's branch needs to incorporate those changes before it can be merged. |
### Rebase Required
When you have multiple milestones in progress and one of them merges, the remaining in-progress milestones may need to incorporate the newly merged code. detects this automatically and shows a **Rebase required** alert on milestones that already have pull requests.
To resolve it, click **Rebase** on the milestone card. The agent incorporates the upstream changes into the milestone branch so that the PR stays mergeable — you do not need to resolve conflicts manually.
***
## Tips
* **Review before approving.** It's much cheaper to fix the plan in the Milestone Spec than to fix generated code. Use Knowledge chat to refine if anything looks off.
* **Use the Review tab before the PR.** The automated review surfaces issues *before* you spend time in your SCM provider. Triage them in Code Review, then read the diff in the PR.
* **Don't rush merges.** Review carefully. It's easier to catch issues now than after several milestones have built on top.
* **Let Milestone Learning do the bookkeeping.** Corrections, fixups, and accepted review comments on a merged PR are automatically distilled into wiki and rule updates — you don't need to write rules by hand for every recurring issue. For conventions you want enforced *now* (before the next merge), you can still add a [Rule](/customization/rules) manually.
* **Work independent milestones in parallel.** If two milestones have no dependency relationship, you can approve and start both. This shortens overall delivery time without sacrificing review quality (subject to pool capacity on self-hosted).
* **Watch for "Rebase required."** When a sibling milestone merges and your in-progress milestone shares dependencies, may flag it as needing a rebase. Trigger the rebase from the milestone card — the agent incorporates the upstream changes so your PR stays mergeable. After a rebase completes, open **Code Review** on that milestone and check the **Rebase Report** tab for a dedicated summary of what was incorporated.
***
## Related Docs
High-level view of your migration
Add new work as a full milestone
Triage milestone review issues with chat
Verify behavior with auto-generated tests
Best practices for PR review
Adjust plans before approving
Choose whether Morph runs the source app, target app, both, or neither
Common issues and how to fix them
# Reviewing Pull Requests
Source: https://docs.modelcode.ai/migration/pull-requests
How to review and merge milestone PRs effectively
Every completed milestone produces a Pull Request in your remote repository (e.g. GitHub, GitLab, Azure DevOps). This is your checkpoint—the moment to verify that the migrated code meets your expectations before it becomes part of your codebase.
## Why PRs Matter
The Pull Request is your safeguard. It ensures:
* **No blind merges** — You see every line of generated code
* **Normal workflow** — Uses the same review process as any other PR
* **Team involvement** — Other reviewers can participate
* **CI/CD validation** — Your existing pipelines run against the changes
## Opening a Milestone PR
1. When a milestone is complete, the milestone card on the **Roadmap** will have an entrypoint to the [**Code Review**](/migration/code-review-chat) drawer.
2. The drawer will have a button that takes you to the individual pull requests
## What to Review
### Code Quality
* Does the generated code follow good practices?
* Are there any obvious bugs or issues?
* Is the code readable and maintainable?
### Correctness
* Does the migration preserve the original functionality?
* Are edge cases handled?
* Do the transformations make sense?
### Consistency
* Does the code match your team's conventions?
* Are naming patterns consistent with existing code?
* Is the style what you expected?
### Tests
* Were tests migrated or generated?
* Do they cover the key functionality?
* Do they pass?
It is also recommended to review the [Validation Hub](/migration/functional-testing) results from the milestone's **Tests** tab, which compares the actual behavior of the origin and target applications side by side.
## Taking Action
### If Everything Looks Good
You can merge from inside , or from your Git provider — whichever fits your process.
**Merge from **
1. Open the [Code Review](/migration/code-review-chat) drawer for the milestone
2. Click **Merge all PRs** in the drawer header
3. Confirm in the dialog, which lists every pull request that will be merged
4. The milestone status updates to **Merged** and the next milestone unlocks
This is the quicker path on a multi-repo milestone, where one milestone produces several pull requests and merging them individually is tedious.
**Merge from your Git provider**
1. Open the pull requests by clicking the **PR links** in the top-right corner of the Code Review drawer
2. Approve each PR in your provider (GitHub, GitLab, Azure DevOps)
3. Merge using your preferred strategy (merge commit, squash, rebase)
4. Return to — the milestone status updates to **Merged**
5. The next milestone unlocks
Two cases where **Merge all PRs** is not available: the **Final Code Delivery** milestone, which must be merged from your provider's pull request page; and any milestone whose branch has fallen behind the feature branch, which needs a [rebase](/migration/milestones-and-tasks#rebase-required) first. Reference-only repositories never produce pull requests and are skipped.
Every pull request for a milestone needs to be resolved — merged, or closed — before the next milestone can begin. While a PR is still open, the milestone stays in its current state and the next one will not unlock.
### If You Find Issues
You have several options:
**Make Manual Fixes**
The PR is a standard Pull Request. You can:
* Push additional commits to fix issues
* Edit files directly
* Clone locally and push changes
Once your fixes are in, merge as normal.
**Ask for More Work**
For significant issues, you might want to do more:
1. Raise the issues in [Code Review chat](/migration/code-review-chat) and ask the agent to fix them on the milestone branch
2. For larger changes, create an [ad hoc milestone](/migration/adhoc-milestones) so the work gets its own plan, validation, and review
Closing a pull request without merging does not send the milestone back for another attempt. treats a closed pull request as a resolved one and marks the milestone **Completed**. To get different code, use one of the two routes above.
### If Checks Fail
CI/CD checks run on PRs automatically. If they fail:
1. Click into the failed check
2. Review the failure reason
3. Common causes:
* Linting violations (may need style adjustments)
* Test failures (tests may need updates for new code)
* Build errors (configuration may need tweaks)
4. Fix the issues and push updates
5. Merge once checks pass
## PR States in
The milestone status reflects the PR state:
| Status | PR State |
| ----------------------------- | ---------------------------- |
| Pending Review | PR open, awaiting review |
| Pending Review (with warning) | PR checks failed |
| Merged | PR merged into target branch |
automatically detects when you merge, updating the milestone status.
## Best Practices
### Review Promptly
Don't let PRs sit. The next milestone is blocked until you merge. Review and merge (or address issues) to keep momentum.
### Use Your Normal Process
Treat milestone PRs like any other PR:
* Add reviewers if your team normally does
* Require approval if that's your policy
* Run additional manual tests if needed
### Check Related Changes
When reviewing, consider:
* Do changes in this milestone connect properly to previous milestones?
* Are there any inconsistencies with already-merged code?
### Document Decisions
If you make manual changes to a PR before merging, consider noting why. This helps if similar issues come up in later milestones.
## After Merging
Once merged:
1. The milestone shows **Merged** status
2. Any milestones that depended on this one are unlocked
3. Sibling milestones that are still in progress may be flagged as **Rebase Required** if they share code dependencies with the just-merged milestone
4. Repeat the process: Review → Generate → Execute → Review PR → Merge
When all milestones are merged, your migration is complete.
### Rebase Required After a Sibling Merge
When you merge a milestone PR while other milestone branches are in progress, those branches may drift from the updated feature branch. detects this and marks affected milestones as **Rebase Required**.
To resolve:
1. Open the affected milestone on the Roadmap
2. Click the **Rebase** action on the milestone card
3. The agent incorporates the upstream changes into the milestone branch
4. Once the rebase completes, review the updated PR as normal and merge
You do not need to resolve merge conflicts manually — the agent handles the integration.
## Troubleshooting
### "PR was closed without merging"
If you accidentally close a PR:
1. Reopen it, or
2. In , retry the milestone to generate a new PR
### "Merge conflicts"
Conflicts can occur if:
* You made manual changes to the repository
* Another branch was merged between milestones
Resolve conflicts as you normally would, then merge.
### "PR stuck in pending state"
If doesn't detect your merge:
1. Refresh page
2. Check that the PR is actually merged
3. Wait a moment—status updates poll periodically
4. Contact support if the issue persists
# Review Issue Assignment
Source: https://docs.modelcode.ai/migration/review-issue-assignment
Assign code review issues to team members and track your assigned reviews in one place
## Assigning Review Issues
When a milestone completes its automated code review, surfaces review issues - bugs, warnings, and improvement suggestions found in the code. You can assign these issues to specific team members so everyone knows who is responsible for triaging each finding.
### How to Assign
1. Open the **Code Review** drawer for a completed milestone.
2. On any open issue card, click **Assign** in the bottom-right corner.
3. A dropdown appears with your team members. Click **Assign to me** to take it yourself, or select another team member.
4. The assignee's name appears on the issue card immediately.
To reassign, click the assignee name and select a different person. To unassign, click the **x** next to the assignee name.
### Email Notifications
When you assign an issue to another team member, they receive an email notification with:
* The issue title and type
* The project and milestone it belongs to
* A direct link to the review drawer
Self-assignment does not send a notification. When an assigned issue is resolved (by the agent or another reviewer), the assignee receives a resolution notification.
### Filtering by Assignee
The Code Review toolbar includes an **Assignee** filter. Select one or more team members to narrow the issue list to only their assigned issues - useful when a team is dividing review work across members.
***
## My Reviews
**My Reviews** gives you a single view of every review issue assigned to you across all projects. Access it from the sidebar.
### What You See
* **Open issues** appear at the top, grouped under an "Open" heading with a count.
* **Resolved issues** appear below in a "Resolved" section, dimmed to indicate they are complete.
* Each card shows the issue title, the project name, and the milestone it belongs to.
* Sized issues carry a **T-shirt-size badge** (XS–XL) showing the estimated effort to address them.
### Search and Filter
Use the **search bar** at the top to find issues by title, project name, or milestone name. Matching text is highlighted in the results.
Use the **Project** filter dropdown to narrow the list to issues from a specific project.
### Navigating to an Issue
Click any issue card to navigate directly to that issue in the Code Review drawer. The drawer opens with the clicked issue expanded and scrolled into view, while other issues remain collapsed.
# Roadmap
Source: https://docs.modelcode.ai/migration/roadmap
How your migration is organized, tracked, and executed
The roadmap is your migration plan, laid out visually. Instead of one massive code change, your migration is split into **milestones** organized by dependency. Each milestone handles a logical chunk of work, produces a pull request, and waits for your approval before anything is merged. Within each milestone, the agent breaks the work into **tasks** and executes them automatically.
This means:
* **Changes are progressive.** Milestones declare dependencies on one another. Independent milestones can run in parallel, while dependent milestones wait until their prerequisites are merged. You catch issues early, before they compound, and the codebase stays working after each step.
* **You stay in control.** Every milestone produces a PR. You review it, run your own tests, and merge when satisfied. Nothing is merged without your approval.
* **Grouping is logical.** Milestones aren't random file splits. Related files are migrated together, dependencies are respected, and each milestone makes sense as a standalone change.
* **Parallel where possible.** When milestones are independent (no shared file dependencies), they can execute simultaneously — shortening overall delivery time without sacrificing PR review boundaries.
***
## What You See
When you open a project, the roadmap shows a vertical list of milestone cards:
Each card shows:
* **Milestone number and title** (e.g., "M1: Project Foundation & Static Files")
* **Progress bar** showing how many tasks are complete out of the total. As tasks finish, the bar fills in and the percentage updates so you can tell at a glance how far along each milestone is.
* **Status badge** indicating where the milestone is in its lifecycle (Not Started, In Progress, Pending Review, Merged, etc.)
* **Validation level pill** — a small indicator showing the effective [validation level](/setup/validation-level) applied to the milestone (Low, Mid, or High)
* **Test summary** (after execution) — Per-repo functional test results showing passed/total counts for backend tests and test counts for frontend tests, with comparison indicators when origin data is available
Milestones are listed on the roadmap with their dependency relationships visible. Independent milestones can be worked in parallel, while milestones that depend on others remain locked until their prerequisites are merged. Click any milestone card to expand it and see its details, tasks, and available actions.
The roadmap sidebar also provides access to the **Project Knowledge** drawer, where you can view and edit the [lifecycle configuration](/setup/build-environment/lifecycle-setup) for the origin and target sides of your migration, and the **Validation Level** drawer to control how deeply each milestone is validated.
Between milestones you may also see a **Rerun Validation Suite** button. This appears when the project's validation level has been upgraded since a milestone was merged, allowing you to retroactively validate at the new depth. See [Validation Level — On-Demand Rerun](/setup/validation-level#on-demand-validation-rerun) for details.
***
Generating the roadmap takes a few minutes, and the progress view shows where you are in the wider flow — the spec drafted and approved, the milestones being planned, the code still to come.
## The Milestone Cycle
Every milestone follows the same pattern:
1. **Review** the milestone plan. Check the relevant files, test files, and description. Edit anything that doesn't look right.
2. **Approve & Start** to kick off the agent. It plans the tasks, executes them one by one, and commits code after each.
3. **Review the Pull Request** when the agent finishes. Morph creates a PR automatically.
4. **Merge** when you're satisfied with the changes.
Once merged, the milestone is marked complete and any milestones that depended on it are unlocked. The full walkthrough with screenshots and details on every status is in the Milestones guide.
The full walkthrough: the milestone lifecycle, statuses, task dependencies, and tips
***
## Related Docs
The milestone lifecycle, statuses, and task dependencies
Best practices for PR review
Adjust plans before approving
Verify behavior with auto-generated tests
Encode preferences for better results
Configure how your project builds and runs
Control how deeply each milestone is validated
# Quickstart
Source: https://docs.modelcode.ai/quickstart
Create your first migration project in minutes
This guide walks you through creating a migration project and getting to your first milestone.
## Prerequisites
* A GitHub, GitLab, or Azure DevOps account
* One or more repositories you want to modernize
## Before You Start: See a Finished Migration
If you would rather see the whole thing working before connecting a repository, ships a **read-only sample project** — a real modernization, replayed end to end.
You can reach it when you are asked to connect a Git provider, without connecting one.
It walks through the whole migration in four phases:
| Phase | What you see |
| ----------- | ------------------------------------------------------------------------------------------------------------ |
| **Set up** | Choosing a build environment and setting modernization goals |
| **Plan** | The specification being generated, reviewed, and approved; picking a validation level; the roadmap appearing |
| **Build** | The first milestone executing, being reviewed and corrected, then merged — and the rest following |
| **Deliver** | The final delivery pull request |
Chat replays the real conversation recorded during that migration, so you can see how the agent was directed. Nothing writes to your account, and nothing you do there affects anything.
It is the fastest way to judge whether fits your codebase, and a good thing to send to a colleague who wants to see the product without starting a trial.
***
## Step 1: Sign In
Go to [modelcode.ai](https://modelcode.ai) and sign in with your account.
## Step 2: Connect Your Git Provider
After signing in, connect your Git provider to access your repositories:
1. Click **Connect GitHub** (or the equivalent for your provider — see [GitLab Integration](/setup/gitlab-integration) or [Azure DevOps Integration](/setup/azure-devops-integration) for provider-specific setup)
2. Authorize to access your repositories
3. Select which repositories can access
You can grant access to specific repositories only. You can always add more later.
## Step 3: Create a Project
1. Click **Create Project** on the Projects page
2. Select one or more repositories from the dropdown
3. For each repository, confirm or change the **origin branch**
4. Click **Continue** to move to the next step
5. Set a **feature branch** name (prefixed with `morph-`)
6. If [Organizational Knowledge](/customization/shared-knowledge) is available, click **Manage** to browse and select items to import, or leave as "starting fresh"
7. Click **Continue** again
8. Enter a project name (auto-filled from your first repository name)
9. Click **Create Project**
clones your repositories and prepares them for analysis. This takes a few moments.
You can add multiple repositories to a single project. This is useful when your modernization spans several repos — for example, migrating a backend and a shared library together.
## Step 4: Set Up the Build Environment
Once your project is created, the onboarding flow guides you through configuration. The first step is choosing where builds and runs your code: the **cloud** environment, or a [Self-hosted Daemon](/setup/build-environment/self-hosted-daemon) for projects that depend on private services.
If your project builds and runs with standard, publicly accessible dependencies, the cloud environment works out of the box. Use a Self-hosted Daemon only when your project requires access to private registries, internal APIs, or on-premise infrastructure.
## Step 5: Define Your Modernization Goals
This is where you tell what you want to achieve. Describe your goal in plain language:
**Examples:**
* "Translate the source code from Ada to C++"
* "Upgrade Python 2.7 to Python 3.12"
* "Migrate from AngularJS to React with TypeScript"
* "Upgrade Java Spring framework to the latest version"
Be specific about your target. Instead of "modernize the code," say "migrate from Express.js to FastAPI" or "upgrade to React 18 with hooks."
### Project Overview
As part of defining your goals, you'll configure the **Project Overview** — a summary of the repositories involved and their roles in the migration:
* **Repos at start** — The repositories you're beginning with and their current state
* **Repos at end** — The target repositories after migration, including any new repos and each repo's modernization role (Modified, New, Reference Only, One-to-One Migration)
## Step 6: Review and Approve the Project Spec
generates your **Project Spec** — the full migration plan for your project. The first time it is ready, [**Project Knowledge**](/customization/project-knowledge) opens automatically on the Roadmap. Select **Project Spec** in the tree if needed, and review it carefully:
* Does it capture your intent?
* Are the target technologies correct?
* Is anything missing?
You can:
* Use **Knowledge chat** in Project Knowledge to ask questions and request updates to the Project Spec
* Run **Auto-review** to have check the spec against the codebase and your goals
* **Approve** from the Project Knowledge drawer when you're satisfied
Take time to review before approving. You can still refine the spec with Knowledge chat afterwards, but once milestone planning has run those edits apply to future milestones only.
## Step 7: Choose a Validation Level
Pick how thoroughly should verify each milestone — from build-and-test only, up to full origin-vs-target verification. See [Validation Level](/setup/validation-level) for what each level covers and what it costs.
## Step 8: Project Setup
At the **High** validation level, needs to know how to actually build, run, and health-check your application. The **Project Setup** stage opens [**Project Knowledge**](/customization/project-knowledge) with **Knowledge chat**, and the agent works through it with you:
1. It inspects the repository and reports the install, build, run, and health-check commands it found
2. It asks you about anything it can't infer — ports, service URLs, credentials (via an encrypted **Provide Secret** card)
3. It runs the whole lifecycle end to end to prove the configuration works
When it passes, the setup is marked **Validated**. See [Lifecycle Setup](/setup/build-environment/lifecycle-setup) for the full walkthrough.
At the Low and Mid validation levels this stage is skipped — never builds or runs the original application, so there is nothing to configure.
## Step 9: Generate Roadmap
generates a **Roadmap** — a sequence of milestones that progressively execute your migration. Each milestone represents a logical chunk of work, ordered so each builds on the previous one.
## Step 10: Execute Your First Milestone
1. Open the first milestone — the **Project Knowledge** drawer opens with the milestone plan
2. Review what it will accomplish (title, description, relevant files)
3. Click **Approve & Start** at the bottom of the drawer to launch the agent
The agent generates tasks from the approved plan and executes them. When complete, a Pull Request appears in your repository. Review it, and when satisfied, merge it to complete the milestone.
## What's Next
* [GitHub Integration](/setup/github-integration) — Manage repository access
* [Lifecycle Setup](/setup/build-environment/lifecycle-setup) — Set up how your project builds and runs, with the agent in chat
* [Validation Level](/setup/validation-level) — Choose how thoroughly each milestone is verified
* [Build Environment](/setup/build-environment/self-hosted-daemon) — Set up a Self-hosted Daemon for private dependencies
* [Define Modernization Goals](/setup/modernization-goals) — Learn how to write effective goals
* [Reviewing the Project Spec](/setup/reviewing-project-spec) — Approve your migration plan using the Project Knowledge drawer
* [Roadmap](/migration/roadmap) — How your migration is organized and tracked
# Azure DevOps Integration
Source: https://docs.modelcode.ai/setup/azure-devops-integration
Connect your Azure DevOps account and configure organization access for Modelcode
Modelcode connects to your Azure DevOps repositories through **Microsoft Entra ID (Azure AD) OAuth**. This guide covers how to sign in with Microsoft, configure your Azure DevOps organizations for access, and create projects using your Azure DevOps repositories.
**Azure DevOps Server is not supported today.** Modelcode only works with
**Azure DevOps Services** (cloud). Support for Azure DevOps Server
(self-hosted) is planned for **H2 2026**.
## Prerequisites
* A Modelcode account (sign up at [modelcode.ai](https://modelcode.ai))
* A Microsoft account with access to one or more Azure DevOps organizations
* **Organization admin** access for the Azure DevOps organizations you want to onboard
## How It Works
Modelcode uses a **two-step** Microsoft authentication flow. You will see **two separate Microsoft login screens** — this is expected and required.
| Login | Purpose | What happens |
| ---------------- | ----------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **First login** | Authenticates your identity via Microsoft Graph | You sign in on Modelcode's login page. This creates your Modelcode session and verifies who you are. |
| **Second login** | Authorizes access to Azure DevOps | Modelcode automatically redirects you to Microsoft a second time to obtain an Azure DevOps-scoped token. This token is what allows Modelcode to read your organizations, projects, and repositories. |
The two logins are required because Microsoft issues **separate tokens** for Microsoft Graph (identity) and Azure DevOps (repository access). They cannot be combined into a single sign-in. Modelcode handles the transition automatically — you just need to sign in when prompted both times.
Both logins go to the same Microsoft sign-in page
(`login.microsoftonline.com`). Use the **same Microsoft account** for both. If
Microsoft remembers your session from the first login, the second login may
show an account picker instead of a full password prompt.
## Signing In with Microsoft
### First Login — Authenticate Your Identity
1. Go to [modelcode.ai](https://modelcode.ai)
2. On the login page, click **Sign in with Microsoft**
3. You'll be redirected to Microsoft's sign-in page (`login.microsoftonline.com`)
4. Enter your Microsoft account credentials (work, school, or personal)
5. If prompted, complete any multi-factor authentication (MFA) steps
6. Microsoft redirects you back to Modelcode
At this point your Modelcode session is established, but Azure DevOps access is not yet configured.
### Second Login — Authorize Azure DevOps
Immediately after the first login completes, Modelcode shows a loading screen with the message:
> **"Connecting to Azure DevOps — please sign in when prompted..."**
After a brief pause you are redirected to Microsoft's sign-in page a second time.
1. Microsoft may show an **account picker** — select the same account you used in the first login
2. If this is your first time, you may see a **consent screen** asking you to grant Modelcode permissions to access Azure DevOps on your behalf — click **Accept**
3. Microsoft redirects you back to Modelcode
Once both logins are complete, you'll land on the **Projects** page with Azure DevOps connected.
If you are already signed in to Microsoft in your browser, the second login
may complete automatically without any visible prompt. This is normal — it
means Microsoft was able to issue the Azure DevOps token silently.
## Configuring Your Azure DevOps Organization
After connecting, Modelcode displays a **Setup Checklist** on the Projects page. You must complete these steps for each Azure DevOps organization and project you want to onboard.
If these steps are not completed, Modelcode will not be able to discover or
access your repositories — even though the Microsoft sign-in succeeded.
### Step 1: Enable Third-Party OAuth Access
Azure DevOps organizations block third-party OAuth applications by default. You must enable this policy for Modelcode to access the organization.
1. Go to your Azure DevOps organization: `https://dev.azure.com/{your-org}`
2. Click **Organization Settings** (bottom-left gear icon)
3. Navigate to **Policies** under the **Security** section
4. Toggle **Third-party application access via OAuth** to **On**
This is an organization-level setting. If you belong to multiple
organizations, repeat this for each one you want to onboard.
### Step 2: Add the Modelcode Application as a User
Modelcode's application identity needs to be added as a user in your organization so it can access projects and repositories.
1. Go to **Organization Settings** → **Users**
2. Click **Add users**
3. Add the Modelcode application identity (shown during onboarding or provided by your admin)
4. Set the **Access Level** to at least **Basic**
5. Grant access to the projects you want to onboard
### Step 3: Grant Project Administrator Permissions
For Modelcode to create branches and manage repository operations within a project, the application identity needs the **Project Administrator** role.
1. Navigate to the Azure DevOps project you want to onboard
2. Go to **Project Settings** (bottom-left gear icon)
3. Navigate to **Permissions** under the **General** section
4. Find the **Project Administrators** group
5. Add the Modelcode application identity to this group
Without Project Administrator permissions, Modelcode will be able to read
repositories but will not be able to create branches or push changes during
the migration.
### Repeat for All Organizations and Projects
These three steps must be completed for **every Azure DevOps organization and project** you intend to onboard to Modelcode:
| Step | Where | Scope |
| --------------------------- | -------------------------------- | ---------------- |
| Enable third-party OAuth | Organization Settings → Policies | Per organization |
| Add application as user | Organization Settings → Users | Per organization |
| Grant Project Administrator | Project Settings → Permissions | Per project |
If you manage multiple organizations, you can complete steps 1–2 for all of
them first, then work through step 3 for each project within those
organizations.
## Creating a Project with Azure DevOps Repositories
Once your organization is configured:
1. Click **Create Project** on the Projects page
2. Enter a project name
3. Modelcode automatically discovers all repositories across your connected organizations and projects
4. Select one or more repositories from the dropdown
5. For each repository, confirm or change the **origin branch**
6. Set a **feature branch** name (prefixed with `morph-`)
7. Click **Create Project**
Modelcode extracts the Azure DevOps organization and project from each repository automatically — no manual entry is needed.
## Approving a Migration Plan
When reviewing and approving a migration plan for an Azure DevOps project:
1. Open **Project Knowledge** from the **Roadmap** (**Modernization** → **Project Knowledge**) with **Project Spec** selected
2. Review the generated migration plan
3. For each new repository in the plan, select the **Azure DevOps organization** from the dropdown
4. Select the **Azure DevOps project** where the output repository should be published
5. Click **Approve**
The organization and project dropdowns are populated from your connected Azure DevOps account. If they are empty, verify that the setup steps above are complete.
## Troubleshooting
### "No Repositories Found"
If Modelcode says Azure DevOps is connected but no repositories are available:
1. Verify **Third-party application access via OAuth** is enabled (Step 1)
2. Confirm the Modelcode application identity is added as a user (Step 2)
3. Check that the application has access to the correct projects
4. Try clicking **Reconnect Azure DevOps** to re-authenticate
### "Azure DevOps organization dropdown is empty"
If the organization or project dropdowns are empty when approving a migration plan:
1. Ensure at least one organization has third-party OAuth enabled
2. Verify the application identity has been added to the organization
3. Refresh the page — the dropdowns are populated from a live API call
### "Why am I seeing two Microsoft logins?"
This is expected. The first login authenticates your identity with Microsoft Graph. The second login authorizes Modelcode to access Azure DevOps. Microsoft requires separate tokens for these services, so two sign-in prompts are necessary. See [How It Works](#how-it-works) above for details.
If the second login fails or you dismiss it:
1. Go back to [modelcode.ai](https://modelcode.ai) and sign in again
2. Both logins will repeat — complete them both
3. If you see an error like "interaction\_required", your browser may be blocking the redirect — allow pop-ups from `login.microsoftonline.com`
### "Second login shows a different account"
If the account picker during the second login shows accounts you don't recognize or defaults to the wrong one:
1. Select the same Microsoft account you used for the first login
2. If the correct account isn't listed, click **Use another account** and enter your credentials
3. Both logins must use the same Microsoft account for the connection to work
### "Permission denied" errors during migration
If Modelcode encounters permission errors when creating branches or pushing code:
1. Verify the application identity has the **Project Administrator** role (Step 3)
2. Check that the permissions apply to the specific project containing the target repository
3. If the project was recently added, wait a few minutes for permissions to propagate
## Next Steps
* [Quickstart](/quickstart) — Create your first migration project
* [Define Modernization Goals](/setup/modernization-goals) — Write effective goals for your migration
* [Reviewing the Project Spec](/setup/reviewing-project-spec) — Learn how to review and approve your migration plan
# Acceptance Criteria
Source: https://docs.modelcode.ai/setup/build-environment/acceptance-criteria
Quality-gate threshold checks Morph runs on every milestone PR
**Acceptance criteria** are project-scoped quality gates that checks on every milestone pull request. Each one is a quantitative, deterministic threshold — "lint warnings must be ≤ 0", "line coverage must be ≥ 80%", "p95 test runtime must be ≤ 30s" — that the modernized code has to satisfy before a milestone can ship.
Acceptance criteria build directly on your **[Lifecycle Setup](/setup/build-environment/lifecycle-setup)**: each custom criterion runs one or more of your lifecycle scripts and reads a measurable signal from its output. Setting them up is **optional** — a project ships fine with only the built-in gates — but they let you encode the quality bar your team already cares about so enforces it automatically.
***
## Built-in vs. custom criteria
Acceptance criteria come in two flavors.
**Built-in** criteria ship out-of-the-box and are inherited from your lifecycle scripts — you don't configure them:
| Criterion | When it applies | What it checks |
| ---------------------- | ------------------------------------- | ----------------------------------------------------------------------------------- |
| **Build must succeed** | Your lifecycle has a **build** script | The project builds without errors (compile / type-check / link errors surface here) |
| **Tests must pass** | Your lifecycle has a **test** script | The configured test suite passes end-to-end |
**Custom** criteria are the ones you define for your project. Each custom criterion checks an **aggregate metric against a fixed absolute threshold**, measured from a single snapshot (one script run), and can include multiple metrics. Common examples:
* Lint warnings must be ≤ 0
* Line coverage must be ≥ 80%
* Max cyclomatic complexity must be ≤ 10
* High-severity audit findings must be 0
* p95 test runtime must be ≤ 30s
Acceptance criteria are **not** tests. A test asserts a specific behavior ("`add(2, 2)` returns `4`", "the login endpoint returns 200"). An acceptance criterion gates an aggregate number against a fixed threshold. Behavior assertions belong in your test suite, where the built-in **Tests must pass** criterion already gates them.
A criterion can also gate **several metrics at once** (for example one `code_coverage` criterion requiring both line coverage ≥ 80% **and** branch coverage ≥ 70%), or span **multiple services** (one `lint` criterion measuring both a backend and a frontend script). In those cases every threshold must pass for the criterion to pass.
***
## How criteria are set up
You define acceptance criteria **through the chat**, without filling out a form by hand. There are three ways they get created:
1. **During onboarding (optional).** After your lifecycle is validated, asks whether you want to set up acceptance criteria. If you say yes, it walks you through discovering extra named scripts (lint, coverage, and so on), auto-suggesting criteria from those scripts, and adding any custom ones. If you skip, you can do all of this later from the chat.
2. **Auto-discovery.** Ask the chat something like *"what acceptance criteria would you suggest?"* and inspects your lifecycle scripts, runs them, and proposes threshold gates from the signals it finds. For example: "I see `npm run lint` reports 12 warnings — should we gate PRs so the warning count never goes up?". You accept, adjust the threshold, or decline each proposal.
3. **Manual requests.** Describe a check in plain language — *"add a criterion that line coverage stays at or above 80%"* — and confirms the exact metric and threshold with you before saving it.
When proposes a criterion, it shows you the value it measured on your source app and suggests a sensible threshold. Choose the current value to prevent regressions, or a stricter threshold to drive improvement.
***
## Baselines
When a custom criterion is added, captures a **baseline** — a one-time measurement of the metric on your source (origin) application. The baseline is the reference point milestone results compare against, so you can see whether the modernized code held the line, improved, or regressed.
Baseline capture runs in the background. How long it takes depends on the lifecycle scripts it has to run. Each criterion shows its baseline state as a badge:
| Badge | Meaning |
| ----------------------------------- | -------------------------------------------------------------------------------------------- |
| **Baseline captured** | The metric was measured on origin and is ready to compare against |
| **Baseline pending** | Capture is queued or running |
| **Baseline stale — script changed** | A referenced lifecycle script changed; the baseline needs to be re-measured |
| **Orphaned — script missing** | A referenced lifecycle script no longer exists (see [Orphaned criteria](#orphaned-criteria)) |
| **Baseline N/A** | A target-only criterion with no origin counterpart, so there is nothing to baseline |
Changing a criterion's threshold or the script it reads, or editing the underlying lifecycle script, invalidates the baseline. automatically re-measures it in the background after such a change.
***
## Origin and target criteria
Like lifecycle configuration, acceptance criteria are tracked separately for **origin** (your source application) and **target** (the modernized application). The Acceptance Criteria view has **Origin** and **Target** tabs.
* New criteria default to **origin**.
* Most origin criteria are **translated to the target automatically** so the same quality bar applies to the modernized stack — even when the toolchain differs (for example, a Python linter on origin maps to the equivalent gate on a TypeScript target).
* You can author **target-only** criteria for checks that only make sense on the modernized stack. These have no origin baseline and show **Baseline N/A**.
***
## Viewing your criteria
**Acceptance Criteria** has its own folder under **Project Setup** in the knowledge tree (the sidebar), alongside the **Origin** and **Target** folders. Expand it and select a side:
* **Origin** — criteria for your source application.
* **Target** — criteria for the modernized application (shown once a target config exists).
Selecting either opens the Acceptance Criteria view for that side, which lists your gates under two subsections:
* **Built-in** — the inherited **Build must succeed** / **Tests must pass** gates.
* **Custom** — the criteria you added, each showing its description, the threshold it enforces, the lifecycle scripts it reads (shown as `Script-` chips), and its baseline badge.
***
## How criteria are enforced
During **milestone review**, re-runs each criterion's lifecycle scripts against the milestone's pull request and compares the measured value to the threshold. Results appear in two places:
* The milestone's **Acceptance Criteria** results tab, which shows each metric's baseline value alongside the value measured on this milestone and whether it passed.
* The **[Code Review](/migration/code-review-chat)** flow, where a failing criterion surfaces as an issue you can triage.
A criterion failing doesn't silently block progress — it shows up as a reviewable issue so you can decide how to proceed.
***
## Orphaned criteria
A criterion becomes **orphaned** when one of the lifecycle scripts it reads no longer exists — usually because the script was renamed or removed. An orphaned criterion can't be enforced, and surfaces a warning at the top of the Acceptance Criteria section.
To resolve one, ask the chat to either point the criterion at the correct script or delete it. Re-measuring a baseline can't fix an orphan on its own — the missing script has to be restored or the reference updated first.
***
## Related Docs
Configure the scripts acceptance criteria read from
Choose whether the agent builds and runs your app, or connects to a running one
How milestones are reviewed, executed, and shipped
Triage acceptance-criteria issues found during milestone review
# Daemon Administration
Source: https://docs.modelcode.ai/setup/build-environment/daemon-administration
Install, network access, certificates, registry mirrors, upgrades, and troubleshooting for the self-hosted ModelDaemon
This page is for whoever installs and looks after the ModelDaemon — usually a platform or IT team. For what the daemon is and why you would use one, start with [Self-hosted Daemon](/setup/build-environment/self-hosted-daemon).
## Prerequisites
* A machine on your network that can reach your private services
* A account with an active project
* Outbound HTTPS from that machine (see [Network access](#network-access)). No inbound ports are required.
* A supported operating system
You do **not** need to preinstall language runtimes (Python, Node, Java, Ruby, Go) or package managers (pip, npm, maven, gem). declares what each project needs and installs it into an isolated environment.
On **Windows**, the installer also installs the Microsoft Visual C++ Redistributable if it is missing. On a locked-down host that blocks the download, install it beforehand.
## Supported operating systems
| Platform | Architectures |
| ------------------------------------------------------------------------------------------------------ | ----------------- |
| **Linux** — Ubuntu, Debian, RHEL, Amazon Linux, SUSE, Alpine, and other POSIX-compatible distributions | Intel/AMD and ARM |
| **macOS** — Apple Silicon or Intel | Intel/AMD and ARM |
| **Windows** — Windows 10/11 or Windows Server 2019+ | Intel/AMD only |
Windows on ARM is not supported. The installer detects it and stops before making any changes.
Install each daemon on an operating system matching its pool's platform. A pool only routes work to machines that match.
In 's platform vocabulary, macOS belongs to the **Linux** family, because what the platform choice really decides is whether generated commands are written for a POSIX shell or for PowerShell. A macOS machine joins a Linux pool.
## Network access
All connections are outbound and initiated by the daemon.
More than the daemon needs network access, and they do not all talk to the same place. Your exact hostnames are shown in the daemon's `config.toml` and in the install command the UI generates — read them from there rather than assuming, because the model and result-reporting hosts can differ from the main one:
| Destination | Needed by | For |
| ------------------------------------------------------------------------------------------------------------------ | ------------------------------------- | --------------------------------------------------------- |
| `*.modelcode.ai` — your `job_server_url` | the daemon | receiving work, reporting status |
| Your model-proxy host — the `llm_proxy` value in `config.toml` | the AI agent | model traffic, proxied by |
| Your web host — the same host you sign in to | the AI agent | reporting test results back |
| `pixi.sh`, `prefix.dev`, and the conda-forge CDN | installer and every environment build | the isolated toolchain |
| `registry.npmjs.org`, `pypi.org` | environment build | base packages — see [Registry mirrors](#registry-mirrors) |
| Cloud object storage — the download URLs redirect here, so follow redirects rather than allowlisting the first hop | installer | the daemon binary and install scripts |
| `aka.ms` | Windows installer only | Visual C++ Redistributable |
The two AI agent rows above are worth allowlisting carefully. If the daemon can reach but the agent cannot reach the result-reporting host, **the daemon looks perfectly healthy and test results silently go missing** — you get no error pointing at the network. If frontend test results are absent for no visible reason, check this first.
If your network only permits outbound traffic through an explicit proxy, contact [support@modelcode.ai](mailto:support@modelcode.ai) before you begin so we can confirm the configuration with you.
## Installing
Run the command the UI generates for you — it already contains your API key, your pool name, and the right download for the machine's platform.
Two names are involved, and they are not the same thing:
| UI field | Install variable | What it is |
| --------------- | ---------------- | --------------------------------------------------------------------------------------- |
| **Pool name** | `POOL_NAME` | The pool this machine joins. Every machine in a pool shares it. |
| **Daemon name** | `RUNNER_NAME` | This machine's own name within the pool. Optional — defaults to the machine's hostname. |
If you are following an older runbook, check which variable it passes. `RUNNER_NAME` used to mean the pool; it now means this machine. A runbook that still puts the pool name in `RUNNER_NAME` will register the machine under its own one-machine pool instead of joining yours.
Two related behaviors worth knowing:
* A `POOL_NAME` set in the daemon's environment **overrides the value in `config.toml`** every time it starts, so the file can disagree with reality. Run `mcode config show` to see the pool actually in effect.
* **Re-running the installer without `POOL_NAME` does not clear the existing pool.** "Reinstall to fix it" quietly keeps the old one.
The installer detects the machine's operating system and architecture itself. If you are copying an older command that specifies them explicitly, those values are now ignored — harmless, but they will not override anything.
### Verifying the install
```
mcode version # confirms the binary is present
mcode config show # shows the pool name in effect
mcode logs # follows recent activity
```
Then click **Verify & Continue** in the UI.
On **Windows**, open a new PowerShell window first so the updated `PATH` is picked up.
## Running as a service
Run `mcode install-service` followed by `mcode start` so the daemon returns after a reboot.
| Platform | Notes |
| ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Linux** | Installs a user-level service. If the machine has no user login session — common in containers — it falls back to a simpler supervision mode **with no automatic restart**. If you need restart-on-failure there, ask an administrator to enable user session lingering for the account. |
| **macOS** | Installs a launch agent that restarts on failure. |
| **Windows** | Installs a Windows service named **ModelDaemon**. Requires an elevated (Run as administrator) PowerShell session. If you cannot run as administrator, use `mcode run` in the foreground instead. |
Service logs are written to `logs/build_agent.log` next to the daemon binary. `mcode logs` follows that file.
## Corporate certificates and TLS-inspecting proxies
If your network terminates and re-signs TLS with an internal certificate authority, the daemon needs to trust it. Two settings in the daemon's `config.toml` cover this:
| Setting | Purpose |
| --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `pixi_tls_root_certs` | Trust store used when installing the isolated toolchain. Defaults to your host's own trust store, so a corporate root already installed on the machine is picked up automatically. |
| `ca_cert_bundle` | A certificate bundle for the package managers and tools the agent uses (npm, pip, git, curl, and others). |
There is a platform difference that matters:
* **On Linux**, the host trust store is complete, so the daemon configures the tooling automatically and merges any bundle you supply.
* **On Windows**, the host trust store is populated lazily and cannot be relied on. To cover pip, git, curl, Python and Rust you must supply a **complete** bundle and set `ca_cert_bundle_complete = true`.
A bundle containing no valid certificate is rejected when the daemon starts, rather than failing later in a confusing way.
## Registry mirrors
When installing its base dependencies, the daemon uses public registries:
| Source | Used for |
| ------------------------------------------- | ------------------------------------------- |
| [npm registry](https://registry.npmjs.org/) | Global npm packages in the base environment |
| [PyPI](https://pypi.org/) | The agent package |
Many enterprise deployments cannot use those defaults — an air-gapped network with no public route, or a policy requiring all third-party artifacts to come from an approved internal registry.
Point the daemon at your own mirrors by adding a `[registries]` table to `config.toml`:
```toml theme={null}
[registries]
npm = "https://artifactory.example.com/artifactory/api/npm/npm-virtual/"
pip = "https://artifactory.example.com/artifactory/api/pypi/simple"
```
Registry overrides apply only to **npm** and **pip** during base dependency setup. They do not affect how your own application's dependencies are fetched.
If your mirror requires authentication, configure credentials on the host the way you would for manual `npm` or `pip` use — `.npmrc`, `pip.conf`, or a network policy that allows the daemon's subnet through.
## Keeping the daemon up to date
Run `mcode update` on the host. It downloads the current version, verifies it, replaces the binary, and restarts the service. There is no automatic update.
`mcode update --check` reports whether an update is available or required, without installing anything.
enforces a minimum version. If every machine in a pool is below it, work stops with a message naming the pool and telling you to run `mcode update`. A single out-of-date machine is quietly skipped instead — so if one machine never seems to pick up work, check its version.
## Where things live
| | Linux / macOS | Windows |
| ------------------------------------- | ------------------------------------- | --------------------------------------- |
| Binary, `config.toml`, encryption key | `~/.local/share/modelcode/` | `%USERPROFILE%\.local\share\modelcode\` |
| Command on `PATH` | `~/.local/bin/mcode` | `%USERPROFILE%\.local\bin\mcode.exe` |
| Per-job workspaces | `~/.local/share/modelcode/workspace/` | `%LOCALAPPDATA%\modelcode\workspace\` |
| Logs | `/logs/build_agent.log` | `\logs\build_agent.log` |
The daemon generates an encryption key pair on first run and keeps it in its data directory. Only the public half ever leaves the machine. `mcode uninstall` deletes it along with everything else — use `--keep-data` if you want the configuration preserved.
**Disk space** grows with the number of projects on the machine and the number of separate environments each one declares, plus a package cache. A small single-project host needs a few GB; a monorepo with one environment per service needs considerably more. For a firm figure for capacity planning, contact [support@modelcode.ai](mailto:support@modelcode.ai).
## Command reference
| Command | What it does |
| --------------------------------------------- | ---------------------------------------------- |
| `mcode run` | Run in the foreground |
| `mcode install-service` / `uninstall-service` | Register or remove the background service |
| `mcode start` / `stop` | Start or stop the service |
| `mcode update [--check]` | Update the daemon, or check for updates |
| `mcode config show` / `edit` | Show effective configuration, or edit the file |
| `mcode logs` | Follow the log file |
| `mcode version` | Print the version |
| `mcode refresh-path` | Re-capture the host `PATH` (see below) |
| `mcode uninstall [--keep-data]` | Remove the daemon |
## Troubleshooting
### When a daemon shows as offline
Start with the UI: the project's **Daemon pool** section and the pool details page show each machine's last-known state, which usually tells you whether this is one machine or the whole pool.
If the setup step cannot confirm the daemon, you will see this:
On the host, in order:
1. **Is it running?** Start it again with `mcode start` (service) or `mcode run` (foreground).
2. **Can it reach the network?** Check firewall, proxy, and VPN changes against [Network access](#network-access).
3. **What do the logs say?** `mcode logs` — look for connection or authentication errors.
Common causes:
* The host rebooted and `mcode install-service` was never run, so nothing restarts the daemon
* A VPN disconnect or firewall change blocked outbound HTTPS
* The API key was rotated in the UI but not updated on the host
### When a daemon is running but gets no work
* **Platform mismatch.** A machine whose OS does not match its pool's platform registers and looks healthy, but receives nothing. Check the pool's platform on the pool details page.
* **Architecture pin.** If the pool pins an architecture, machines on other architectures are not sent work.
* **Version too old.** A machine below the minimum version is skipped silently. Run `mcode update`.
### When registration is refused
The daemon reports the reason in its log. Some refusals are permanent — the daemon will disable its own service and exit cleanly rather than retrying forever, so a clean exit is a signal rather than a crash:
| Reason | Retries? | What to do |
| ----------------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------- |
| The pool name does not match a pool that exists | No | Correct the pool name, or create the pool in the UI first. |
| The machine's platform does not match the pool | No | Install on a matching OS, or use a different pool. |
| The pool is at capacity | Yes | Wait for a machine to leave the pool, or ask your administrator whether the pool's limit can be raised. |
| The daemon was deleted in the UI | No | Reinstall to re-register this machine. |
Deleting a daemon in the UI is a real deletion: the machine clears its own registration, stops its service, and stays down until reinstalled.
### "Command not found" after installing new tools
The daemon captures the host `PATH` when it is installed as a service. If you install new tools afterwards, run `mcode refresh-path` and restart the daemon.
### Authentication failures ("Unauthorized", "Authentication failed")
Check that the API key in `config.toml` matches the one shown in the UI. If it was rotated, update the file and run `mcode start` again.
### Build, run, or health-check failures
These are usually about the application rather than the daemon. The [Validation Hub](/migration/functional-testing) shows which script failed and its output.
* **Build fails** — most often a dependency only available on your private network, or a command that needs a different working directory. Verify it by hand on the same machine as the same user.
* **Application does not start** — check the port is free, and that required services are reachable from this host.
* **Health check times out** — confirm the URL and port, check the application binds to `0.0.0.0` or `localhost` rather than a specific interface, and allow more time if startup is slow.
## Migrating from V1
Older "V1" daemons are deprecated but have not been switched off.
* **Existing V1 projects keep working.** There is no forced migration and no deadline.
* **New projects require the current daemon.** A new project cannot attach to a V1 daemon.
**V1 and the current daemon cannot coexist on one machine.** Both install to the same location, so running the current installer on a V1 host **replaces the V1 daemon** and its projects stop running jobs.
If you still have active V1 projects, install the current daemon on a **different machine** with the same network and credential reach. Replace V1 on the original host once those projects are finished.
The practical differences: dependencies and lifecycle commands are now discovered for you instead of being installed and written by hand, each job runs in its own isolated workspace, and encryption keys are managed by the daemon.
# Git Strategy & Branches
Source: https://docs.modelcode.ai/setup/build-environment/git-strategy
How Morph manages branches, commits, and pull requests across your repositories
uses a structured branching strategy to keep your migration organized, reviewable, and safe. Every code change happens on an isolated branch—nothing is merged to your mainline without your explicit approval.
***
## Feature Branch
Every project has a **feature branch** that acts as the integration point for all migration work. This branch is shared across all target repositories in the project.
* **Default name:** `morph-main`
* **Customizable:** You can change the feature branch name during [project creation](/core-concepts#project) if your organization has naming conventions (e.g., `feature/modernization`, `migration/java-to-kotlin`)
* **Scope:** The same feature branch name is used for all target repositories in the project
The feature branch is where completed milestone work accumulates. Each milestone merges into this branch, building up the full migration incrementally.
***
## Project Start Point
At project creation time, records the **commit SHA** of each repository's origin branch. This SHA marks the project's starting point and serves as the baseline for tracking what has changed in the upstream mainline since the project began. You can click the icon next to the repo name (on the top left of the project page) to see those changes.
***
## Upstream Changes
As your team continues pushing changes to the repository's mainline during the migration, makes it easy to stay aware of what's changed.
**Viewing upstream changes:** On the project page, below the project title, you can see a list of all project related repos with a diff icons (). Click it to see all upstream commits pushed to the repository's mainline since the project started (i.e., since the recorded start SHA).
***
## Upstream Sync
Between milestones, you can trigger an **upstream sync** to incorporate mainline changes into your migration. This is useful when significant upstream work has landed and you want the migration to stay aligned with the latest codebase state.
When triggered, upstream sync will:
1. Update the project's starting SHA to the current mainline HEAD
2. Create an **ad-hoc sync milestone** that follows the standard milestone procedure—including code review, functional testing, and PR creation
3. Rebase any in-progress milestone branches so they incorporate the new baseline
4. Adjust the plan for upcoming milestones to account for the upstream changes
The sync milestone goes through the same lifecycle as any other milestone: the agent executes the work, creates a PR, and you review and merge before continuing.
Upstream sync is not supported in projects that were created before this feature was introduced. Only projects created after upstream sync became available can use it.
***
## Milestone Branches
Each milestone gets its own branch, branched off from the feature branch:
* **Naming format:** `-milestone_-`
* **Example:** `payments-api-migration-milestone_3-a1b2c3d4`
This keeps each milestone's work isolated until it passes review. The milestone lifecycle is:
1. creates the milestone branch from the feature branch
2. The agent commits all task work to this branch
3. On completion, creates a **PR from the milestone branch → feature branch**
4. You [review and merge](/migration/pull-requests) the PR
5. Dependent milestones are unlocked; sibling milestone branches may receive a rebase if they share dependencies with the merged code
When milestones are independent (no shared file dependencies), multiple milestone branches can exist simultaneously. Each runs in isolation and produces its own PR. When one of them merges, checks whether remaining in-progress branches need to incorporate the new code. If so, it flags them as **Rebase Required** and the agent handles the integration automatically when you trigger it.
***
## End-of-Project PR
When all milestones are complete and merged into the feature branch, creates a final **Pull Request from the feature branch to the target branch**:
* **Default target:** The repository's default branch (e.g., `main`, `master`)
* **Customizable:** You can select a different target branch during project creation if needed
This final PR represents the entire migration in one reviewable unit. Your team can review it holistically, run CI/CD, and merge when ready.
**Point your project at a branch that will still exist when the migration finishes.** measures the whole migration against the branch you start from, and delivers the final pull request back into it. If that branch is deleted mid-project, the project cannot be recovered and has to be started again.
Use a long-lived branch — `main`, `master`, `develop` — and not a temporary or release branch that may be cleaned up along the way.
***
## Branch Flow Diagram
```mermaid theme={null}
gitGraph
commit id: "existing"
commit id: "project start (SHA recorded)"
branch morph-main
commit id: "milestone 1 merge"
branch milestone-2
commit id: "milestone 2 work"
checkout morph-main
branch milestone-3
commit id: "milestone 3 work (parallel)"
checkout morph-main
merge milestone-2 id: "milestone 2 merge"
merge milestone-3 id: "milestone 3 merge (rebased)"
checkout main
commit id: "upstream changes"
checkout morph-main
commit id: "upstream sync milestone"
commit id: "final milestone merge"
checkout main
merge morph-main id: "end-of-project PR"
```
***
## Supported Git Providers
supports all major Git providers:
GitHub.com integration via GitHub App
GitLab.com integration via OAuth
Azure DevOps Services via Microsoft Entra ID
***
## Summary
| Concept | Details |
| ------------------- | -------------------------------------------------------------------- |
| Feature branch | `morph-main` (customizable at project creation) |
| Milestone branch | `-milestone_-` |
| Milestone PR | Milestone branch → feature branch |
| End-of-project PR | Feature branch → target branch (default: repo default branch) |
| Start point | Commit SHA recorded at project creation |
| Upstream visibility | Diff icon on Roadmap shows mainline changes since start |
| Upstream sync | Updates start SHA, creates sync milestone, rebases affected branches |
***
## Related Docs
How to review and merge milestone PRs
Project setup and branch strategy overview
How your migration is organized and tracked
The milestone execution lifecycle
# Lifecycle Setup
Source: https://docs.modelcode.ai/setup/build-environment/lifecycle-setup
Set up how your project installs, builds, runs, and is health-checked — together with the agent in chat
Every project needs a **Lifecycle Setup** - the scripts, environment variables, and documentation that define how the application installs dependencies, builds, runs, passes a health check, and tests. uses this configuration to validate your setup, run functional tests, and verify milestone output.
You don't fill this in with a form. sets it up **with you in chat**, inside the **Project Knowledge** drawer, during the **Project Setup** stage of onboarding. The agent inspects your repository, proposes the scripts and variables, asks you for anything it can't infer, and runs the whole lifecycle end to end to prove it works.
***
## When Lifecycle Setup Happens
**Project Setup** is a stage on the Roadmap onboarding checklist. It runs **after** you approve the Project Spec and choose a validation level:
1. **Setup Build Environment**
2. **Set Modernization Goals**
3. **Generate Project Spec**
4. **Approve Project Spec**
5. **Choose Validation Level**
6. **Project Setup** ← lifecycle setup happens here
7. **Generate Roadmap**
While the stage is running, the checklist shows it as **Setting up Project…**.
**Project Setup only runs at the High [validation level](/setup/validation-level).** At Low and Mid, skips origin lifecycle setup entirely — the origin application is never built or run, so there is nothing to configure. The target lifecycle is still discovered automatically during the foundation milestone.
If you start at Low or Mid and later upgrade to High, opens Project Setup at that point and runs the same chat flow.
Clicking **Project Setup** opens the Project Knowledge drawer with Knowledge chat already started. The drawer also opens on its own the first time the stage becomes active.
***
## Setting Up the Lifecycle in Chat
The first time you land in Project Setup, the drawer is **chat only** — there is no tree or content pane yet, because there is nothing to show until the agent discovers it. The chat opens on *"Welcome! Time to set up the project and get started"* and starts working.
While the sandbox boots, the chat shows its progress: allocating resources, cloning the repository, installing dependencies, indexing project context. The tree and content pane appear alongside the chat as soon as the agent has something to put in them.
### What the agent works through
The agent maintains a visible to-do list and works through it in order. Which items appear depends on your build environment:
| Phase | When it runs | What happens |
| ----------------------- | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| **Strategy** | Self-hosted only | Asks whether you or will run the app — see [Lifecycle Strategy](/setup/build-environment/lifecycle-strategy) |
| **Dockerfile** | Modelcode Hosted | Builds the container image the project runs in |
| **Dependencies** | Self-hosted | Resolves and installs the toolchain the project needs |
| **Lifecycle** | Always | Discovers and validates the origin install / build / run / healthcheck / test scripts |
| **Script discovery** | Optional | Finds extra named scripts (lint, coverage, and so on) that [acceptance criteria](/setup/build-environment/acceptance-criteria) can read |
| **Acceptance criteria** | Optional | Proposes quality gates from those scripts, then lets you add your own |
Once the lifecycle validates, the agent asks a single question: whether you want to set up [acceptance criteria](/setup/build-environment/acceptance-criteria). Answer **Skip — I'll do this later** and the last three phases are marked skipped and onboarding wraps up there; you can add scripts and criteria from the chat at any point afterwards.
On a self-hosted project that uses the **connect** strategy, the **Dependencies** phase is skipped too — isn't building or running the app, so there is no toolchain to resolve.
For the lifecycle phase specifically, the agent:
1. **Inventories the repository** — framework, install/build/run commands, health-check signals, environment variables, external service dependencies — and reports what it found before writing anything.
2. **Proposes the phases** and confirms them with you. Beyond the standard five, this can include steps like `migrate` or per-service splits in multi-service projects.
3. **Registers the scripts and environment variables**, asking you for values it can't infer.
4. **Executes the lifecycle end to end** to prove it works. On failure it shows you the failing phase, the last lines of output, and a proposed fix before retrying.
### Answering the agent's questions
The agent asks structured questions rather than free-text prompts wherever it can. Pick one of the options or write your own, then click **Submit**. **Skip** leaves the decision to the agent.
### Providing secrets
When the lifecycle needs a credential — an API key, a database password, a service token — the agent asks for it with a **Provide Secret** card instead of asking you to type it into the chat. The value is encrypted immediately and is never shown to the agent or written into the transcript.
Never paste a secret into the chat message box. Use the **Provide Secret** card — anything typed into the chat becomes part of the conversation history.
### When setup finishes
Once the lifecycle validates, the chat confirms it and onboarding continues to **Generate Roadmap**. If the agent can't get the application fully healthy, it asks you to confirm saving the configuration as a **Draft** so you can correct it yourself.
***
## The Project Setup Panel
Once the lifecycle exists, the drawer switches to its full layout: a tree on the left, the selected content in the middle, and chat on the right. **Project Setup** is the branch of the tree that holds everything needs to run your application.
Use **Hide chat** in the toolbar to collapse the chat column and give the content panel the full width — useful when you're reading a long lifecycle document.
The branch is organized by side of the migration:
```
Project Setup
├── Origin
│ ├── Scripts
│ ├── Environment Variables
│ └── Lifecycle Document
├── Target
│ ├── Scripts
│ ├── Environment Variables
│ └── Lifecycle Document
├── Acceptance Criteria
└── Dockerfile (Modelcode Hosted) / Dependencies (Self-hosted)
```
* **Origin** - How the source application builds and runs. Set up with you during Project Setup and used as the behavioral baseline for [functional testing](/migration/functional-testing).
* **Target** - How the destination application builds and runs. Discovered automatically during the foundation milestone (Milestone 1). The **Target** entry stays disabled until then, with the tooltip *"Available once a target lifecycle configuration has been discovered."*
### Scripts
Ordered shell scripts that bring your application to a healthy, running state. They run in the shell for your project's platform — bash on Linux, PowerShell on Windows — which is fixed when you choose the platform during Build Environment setup, not by whichever daemon happens to pick up the work. Write them for that shell.
Common scripts include:
| Script | Purpose |
| --------------- | -------------------------------------------------------------------------------------------- |
| **install** | Install dependencies (e.g., `npm install`, `pip install -r requirements.txt`) |
| **build** | Compile or bundle the application |
| **seed\_db** | Apply database migrations and load any fixture or seed data the application needs to run |
| **run** | Start the application process |
| **healthcheck** | Verify the application is responding (e.g., `curl http://localhost:3000/health`) |
| **smoke** | Exercise the running application enough to prove it actually works, not just that it started |
| **test** | Run the project's test suite |
Two of these are worth explaining, because they are the ones teams do not expect:
**`seed_db`** runs after **build** and before **run**. Many applications start but do nothing useful against an empty database, so separating "prepare the data" from "start the app" means can restart your application without re-seeding it every time.
**`smoke`** is required for the origin application, and it is the check that makes validation meaningful. A health check tells you a process is listening; a smoke test tells you the application works. Until a smoke run passes, does not treat your origin lifecycle as validated — even if every other script succeeded — because a migration validated against an application that was never really working proves nothing.
If your lifecycle looks validated and then returns to **Draft**, a failing or missing smoke script is the usual reason. The status banner names what needs attention.
Click a script name to expand it. The expanded view shows:
* **Inline code editor** - Edit the script content directly. Scripts are executed as shell commands.
* **Logs** - The stdout output from the last validation run, with the exit code and duration.
* **Errors** - The stderr output. A bug icon appears on the script header if the last run failed with stderr output.
Scripts run in order, and you can drag the handle on a script to reorder it. To add one, click **Add Script**, enter a name, and press Enter. To remove one, expand it and click **Delete**.
### Environment Variables
Key-value pairs your application needs at build or runtime. Variables discovered from the codebase are pre-populated; you can add, edit, or remove them with **Add Variable**.
Variables marked as **secrets** are encrypted at rest. Tick the **Secret** checkbox on a variable to mark it as a secret; once marked, the value is masked and a show/hide eye icon appears so you can reveal it when needed.
### Lifecycle Document
A markdown overview describing how the application is structured, the execution order of scripts, and how each phase fits together. The agent generates it during Project Setup. It is **displayed read-only in the panel** — ask Knowledge chat to change it.
A marker in the section header shows who wrote the configuration last: **Auto-discovered** when the agent did, **User-modified** once you save an edit of your own from the panel.
### Dockerfile and Dependencies
These artifacts are **read-only in the panel** too — they carry the hint *"Read-only — ask the chat to update this."* To change the container image or the dependency manifest, ask Knowledge chat.
***
## What You Edit Directly vs. What the Chat Owns
Both routes are available, and they write to the same configuration.
| Artifact | Edit in the panel | Ask the chat |
| --------------------------------- | :---------------: | :----------: |
| Scripts | ✅ | ✅ |
| Environment variables and secrets | ✅ | ✅ |
| Lifecycle document | ❌ | ✅ |
| Dockerfile | ❌ | ✅ |
| Dependencies manifest | ❌ | ✅ |
| Running validation | ❌ | ✅ |
Only **Scripts** and **Environment Variables** are editable in place — everything else is displayed read-only and changed through the chat. Editing in the panel is best for a small, known correction: a wrong port, a typo in a command. Ask the chat when you want the agent to work out the change itself, touch several things at once, or investigate a failure.
Typical chat asks:
```
The run script should bind to port 8080, not 3000.
Re-validate after the change.
```
```
Add a `migrate` script that runs `alembic upgrade head` before `run`.
```
```
DATABASE_URL should point at a local Postgres on localhost:5432
for validation. Save it as a regular env var, not a secret.
```
***
## Validation Status
The status bar at the top of the Project Setup panel shows the current validation state:
| Status | Meaning |
| --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Validated** | All scripts ran successfully. The application started and passed the health check. |
| **Draft — Needs Review** | could not get the application running and healthy. Review the scripts, fix what's wrong, and re-validate. |
| **Failed** | Validation ran but one or more scripts failed. The output is shown in the banner. |
| **Imported — Needs Verification** | The setup came from [Organizational Knowledge](/customization/shared-knowledge) at the organization level. Confirm it matches this project, then re-validate. |
| **Pending** | Changes have been saved but not validated yet. |
When the status is anything other than **Validated**, a banner explains what to do next and offers a **Re-validate** link. For **Draft** and **Failed**, the banner also includes the raw validation output.
Saving any change to scripts or environment variables resets the status to **Pending** — the saved configuration hasn't been proven to work until you re-validate.
Origin lifecycle status also gates the roadmap: won't generate a roadmap while the origin lifecycle is **Draft**, **Failed**, or **Imported**.
***
## Editing and Re-validating
After making changes in the panel:
1. Click **Save Changes** to persist your edits
2. Click **Re-validate** to run the full validation sequence again
Both buttons sit in the drawer toolbar. **Re-validate** saves any unsaved changes first, then hands the run to Knowledge chat — the agent re-runs the lifecycle end to end, reports what it finds, and writes the result back. You can watch it happen in the chat panel.
If you only need to fix a small script error, edit the script inline and click **Re-validate** - it handles saving for you.
**Re-validate** is disabled while the chat is streaming, with the tooltip *"Wait for the chat to finish before re-validating."* Asking the chat directly works too:
```
Re-validate the origin lifecycle setup.
```
***
## Authentication Handling
When sets up or validates your lifecycle, it probes API routes beyond the health endpoint to check whether the application has authentication that could affect automated testing.
### What Morph handles automatically
can detect and handle two types of authentication without manual intervention:
* **Disable flags** — Many frameworks offer an environment variable or config setting that disables authentication in development or test mode (for example `DISABLE_AUTH=true`, `AUTH_ENABLED=false`, or framework-specific flags like `EnableTesting`). When finds one, it registers the variable, restarts the application, and verifies that protected endpoints are now accessible.
* **Static tokens** — If the application uses a fixed API key or Bearer token (e.g. an `X-API-Key` header), asks you for the token with a **Provide Secret** card, stores it encrypted, and adds a verification script that confirms the token works.
In both cases, adds an **authcheck** lifecycle script that hits a protected endpoint with the configured auth method and fails if authentication is not working. This script runs alongside your other lifecycle scripts during every validation.
### What requires your attention
* **Session-based login (username/password)** — Applications that require a `POST /login` call to obtain a session cookie or Bearer token. reports this as detected but unsupported for automated bypass.
* **OAuth / SSO / MFA** — External identity provider flows that involve browser redirects, third-party consent screens, or multi-factor challenges. These cannot be automated.
When detects these types, it documents the finding and shows an **"Unsupported Authentication Detected"** banner in the Project Setup panel. The banner explains that validation steps requiring authenticated access may be skipped, along with details about the specific auth type found.
** cannot bypass login flows, external identity providers, or multi-factor challenges.** If your application relies on OAuth, SSO, MFA, or a `POST /login` session handshake, those auth-protected routes will be **unreachable during automated testing**. You have two options:
1. **Follow one of the [manual steps below](#manual-steps-for-unsupported-auth-types)** to configure authentication yourself (e.g. add a disable flag, seed a test user, add a login script, or use the connect strategy).
2. **Accept reduced functional testing coverage.** will still validate install, build, run, and health check — only runtime behavior verification of auth-gated endpoints is skipped.
### Manual steps for unsupported auth types
If can't figure out your application's auth automatically, you can prepare the environment yourself so that protected surfaces become reachable. Below are common patterns — pick the one that fits your stack. You can apply any of them by asking the chat, or by editing the panel directly.
#### Add a test-mode environment variable
Most frameworks have a way to relax or skip authentication in non-production environments. Add that variable to the **Environment Variables** section, for example:
| Framework / Pattern | Variable | Value |
| -------------------- | ------------------------ | --------------------- |
| Generic disable flag | `DISABLE_AUTH` | `true` |
| Rails / Devise | `RAILS_ENV` | `test` |
| Django | `DJANGO_SETTINGS_MODULE` | `myapp.settings.test` |
| Spring Boot | `SPRING_PROFILES_ACTIVE` | `test` |
| .NET | `ASPNETCORE_ENVIRONMENT` | `Development` |
| Express / Passport | `AUTH_ENABLED` | `false` |
Re-validate after the change so confirms protected endpoints are now reachable.
#### Seed a test user and add a login script
If your application uses session or token-based authentication, the alternative is to give a way in rather than switching authentication off. That takes two scripts:
1. **A `seed_db` script** that creates a test user, using whatever your project already uses for this — your ORM's console, a management command, a seed script, or a SQL fixture.
2. **An `authcheck` script**, ordered after `healthcheck`, that logs in as that user and confirms a protected endpoint responds. It should exit non-zero if that fails, so a broken login surfaces as a failed script rather than as confusing test results later.
You do not have to write either from scratch. Describe your authentication setup in chat and ask the agent to add them — it can read how your application does authentication and propose scripts that fit, which is usually faster and more accurate than adapting a generic example.
3. **Store the test account's credentials as secrets** in the environment variables section so they are encrypted at rest.
#### Use the connect strategy with a pre-authenticated instance
When none of the above options work (e.g. OAuth with an external IdP that cannot be mocked), consider the **[connect strategy](/setup/build-environment/lifecycle-strategy#you-run-your-app-connect)**. Run the application yourself with authentication already configured, and point at the live, authenticated instance. skips install/build/run and only needs a base URL and health check.
***
## Origin and Target
maintains separate lifecycle configurations for each side of the migration.
| | Origin | Target |
| ------------------ | ---------------------------------------------- | ------------------------------------------------------------------------------- |
| What it describes | How the source application builds and runs | How the modernized application builds and runs |
| When it's set up | Project Setup, with you in chat | Automatically, during the foundation milestone (Milestone 1) |
| What it's used for | The behavioral baseline for functional testing | Verifying that migrated code actually builds, runs, and passes its health check |
Target discovery reuses the origin configuration as a starting point, so a clean, accurate origin setup directly improves the target result. Both sides stay editable in the panel and through chat for the rest of the project.
***
## Tips
* **Check the Errors tab first.** When a script fails, the stderr output usually points directly at the problem - a missing dependency, a wrong port, or a typo in the command.
* **Keep scripts minimal.** Each script runs in a fresh shell process. If two commands need to share shell context — activating a virtual environment before running a command, say — chain them in a single script: with `&&` on Linux and macOS, and with `;` or separate lines on Windows.
* **You don't need to change directory.** keeps the working directory consistent across every command in a job. Only `cd` when a command has to run in a nested folder.
* **Set environment variables in the UI, not in your scripts.** Variables added to the **Environment Variables** section are available to every script and can be encrypted if sensitive. A variable exported inside one script does not survive into the next.
* **Private dependencies need credentials on the machine.** Scripts run exactly as written. If your package manager needs to authenticate to a private repository, those credentials have to be present on the host already, or supplied as an encrypted environment variable.
* **Use environment variables for configuration.** Avoid hardcoding ports, database URLs, or API keys in scripts. Set them as environment variables so they are easy to change and can be encrypted if sensitive.
* **Answer the agent's questions rather than skipping them.** A skipped question means the agent guesses, and a wrong guess usually surfaces later as a validation failure.
* **Reuse a working setup.** Once the lifecycle validates, it becomes available as [Organizational Knowledge](/customization/shared-knowledge) so the next project on the same repositories can import it and skip Project Setup.
***
## Related Docs
The drawer that hosts Project Setup, Knowledge chat, and the rest of your project context
Choose whether the agent builds and runs your app, or connects to a running one
Why Project Setup only runs at the High validation level
Quality gates built on top of your lifecycle scripts
Run ModelDaemon on your own infrastructure for projects with private dependencies
Where lifecycle script results are reported during milestone execution
# Lifecycle Strategy
Source: https://docs.modelcode.ai/setup/build-environment/lifecycle-strategy
Choose whether the agent builds and runs your app from source, or connects to an app you already have running
During the **Project Setup** onboarding stage, asks **how the agent should access your app**. This is the lifecycle strategy, and it determines whether brings your application up itself or talks to an instance you keep running. The choice shapes how lifecycle scripts, health checks, and functional testing work for the rest of the project.
The question arrives as the first thing the agent asks in **Knowledge chat**, before it starts discovering anything — the answer determines whether there are install, build, and run scripts to discover at all.
**The lifecycle strategy choice only applies to the [Self Hosted](/setup/build-environment/self-hosted-daemon) build environment** (where you run **ModelDaemon** on your own infrastructure). The **connect** strategy depends on the daemon being able to reach an app you keep running, which is only possible when the daemon lives inside your network.
If you're on **[Modelcode Hosted](/setup/build-environment/modelcode-hosted)**, there is no choice to make: always uses the **managed** strategy. The hosted sandbox builds and runs the app for you, and it can only reach **publicly accessible** dependencies and services (public package registries, public APIs). It cannot reach private databases, internal APIs, or private registries — if your app needs those, use Self Hosted.
## Why the agent needs runtime access
modernizes your code. A lot of that work can be done statically — reading the source, reasoning about it, and rewriting it. But code that only looks correct on paper isn't enough. When the agent can actually **run the application and observe its behavior at runtime**, the quality of the results goes up substantially: it validates changes against a working app, catches regressions early, and uses functional tests to confirm the modernized code behaves like the original.
That runtime access has two requirements:
* **Access to the origin application** - so the agent can observe the original behavior and use it as the baseline it modernizes toward. You grant this with one of the two strategies below (**connect** or **managed**).
* **Access to external services and dependencies** - databases, internal APIs, message queues, private registries, and anything else the app talks to. The target (modernized) application needs these at runtime just as the origin does, so the build environment must be able to reach them.
***
## The two strategies
* **Morph runs your app** (managed) - installs, builds, runs, and tears down your application from source, owning its lifecycle on every run.
* **You run your app** (connect) - You keep the application running, up, and reachable yourself, and the agent connects to that live instance.
The trade-off is **setup speed vs. ownership**: **connect** is much faster to set up, but you take care of running the app — keeping it up and tearing it down stays your responsibility; **managed** can take longer to set up, but after that takes care of running the origin app for you.
***
## Morph runs your app (managed)
With the **managed** strategy, takes care of running the app — it owns the full lifecycle: running it, keeping it up, and tearing it down. The agent automatically discovers the install, build, and run scripts by analyzing your codebase, then uses them to start your application from source inside the build environment. runs the health check and test commands against the app it started. You review the discovered scripts and correct them if needed — you don't author them from scratch.
Setup can take a little longer here, because the agent has to discover and validate how to build and run the app before the project starts. The payoff is that you hand the origin app's lifecycle to : it brings the app up from a known, reproducible state on every run and tears it down afterward, so you don't have to run or keep anything up yourself.
Even though runs the app for you, the **external services and dependencies** your app relies on — databases, internal APIs, message queues, private registries, and so on — still need to be running and reachable from the build environment. The agent can build and start your app, but it can't stand up the infrastructure behind it.
Choose this when:
* can build and run your app from source.
* You are comfortable setting up the environment yourself.
Because every run starts from a known, reproducible state, this strategy gives the agent the most control over the application and a consistent baseline to test against.
***
## You run your app (connect)
With the **connect** strategy, you take care of running the app and does not build or run it. Instead, you point it at an application that is **already running** on your infrastructure, and the agent interacts with it directly over its base URL. Install, build, and run steps are skipped; the agent only probes the running instance via a health check.
This strategy is **only available with the Self Hosted build environment**, because the ModelDaemon has to be able to reach the running app from inside your network.
Setup is much faster because there's nothing to discover, build, or validate up front — you just provide the URL. The trade-off is that the origin app's lifecycle stays **your responsibility**: only probes the instance you point it at, so running it, keeping it up and healthy, and tearing it down for the duration of the project is on you.
You provide:
* **Base URL** - The root URL where your application is accessible (for example, `http://localhost:8000`).
* **Health Check Command** - A command that confirms the app is reachable and healthy (for example, `curl -f http://localhost:8000/health`).
* **External services and dependencies** - The databases, internal APIs, message queues, private registries, and any other services your app talks to must be running and reachable from the build environment. The target (modernized) application needs them at runtime just as the origin does.
Choose this when:
* Your application is already deployed and running, and you want the agent to work against that instance.
* You want to get started quickly and are comfortable keeping the origin app running yourself.
* Building or running the app from source inside the build environment is impractical (for example, it depends on infrastructure the build environment cannot reproduce).
**Keep the origin app running.** With the **connect** strategy, the origin app's lifecycle is your responsibility — only probes the instance you point it at. If that app goes down or its base URL is unreachable, **functional testing quality is degraded**: the agent can't compare the modernized code against the original's live behavior, so regressions are more likely to slip through.
***
## A note on shell syntax
Whichever strategy you pick, the commands you supply run in the shell for your project's platform — bash on Linux, PowerShell on Windows. The platform is chosen once during Build Environment setup and does not change, so commands written for one are never re-interpreted for the other.
## Which should I pick?
| | Morph runs your app (managed) | You run your app (connect) |
| --------------------------- | --------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- |
| Setup speed | Slower — discovery + validation up front | Faster — just provide a URL |
| Origin app lifecycle | Managed by on every run | Your responsibility to keep running |
| Who runs the app | builds and runs it from source | You keep it running |
| Install / build / run steps | Auto-discovered and executed by the agent | Skipped |
| What you provide | Review and correct the discovered scripts; access to external services and dependencies | Base URL + health check command; access to external services and dependencies |
| Best for | Apps that build cleanly from source | Apps already deployed and running |
Pick based on the trade-off above: **connect** gets you started fastest if you already keep the app running, while **managed** hands the origin app's lifecycle to once it's set up.
***
## Related Docs
Configure the scripts, environment variables, and health checks the agent uses
Let Modelcode provision a secure sandbox to build and test your app
Run ModelDaemon on your own infrastructure for projects with private dependencies
Build environment terminology and mental model
# Modelcode Hosted
Source: https://docs.modelcode.ai/setup/build-environment/modelcode-hosted
Let Modelcode spin up a secure sandbox to build and test your application - no installation required
can provide a fully managed build environment for your project. When you choose the **Modelcode Hosted** option, automatically provisions a secure sandbox and handles all infrastructure setup on your behalf. There is nothing to install, no daemon to configure, and no environment to maintain.
## Choosing your platform
During Build Environment setup you first pick your project's platform — Linux / macOS or Windows — and then choose Modelcode Hosted versus Self hosted. The platform decides the shell your lifecycle scripts are written in and the image your sandbox is built from, and neither choice [can be changed afterwards](/setup/build-environment/switching-environment) — so pick the platform your application already builds on.
Windows is fully supported on Modelcode Hosted. If you write lifecycle scripts for Windows, see the note on [shell syntax](/setup/build-environment/lifecycle-strategy) — the PowerShell version differs between hosted and self-hosted machines.
## Why Use Modelcode Hosted
The hosted environment is the fastest way to get running. Because there is no local daemon to install or manage, onboarding is immediate - works out how to build and run your project [with you in chat](/setup/build-environment/lifecycle-setup) and takes care of the rest.
This option works best for projects with publicly accessible dependencies: open-source packages, public container registries, and services reachable from the internet. If your project already builds cleanly from source using publicly available dependencies, the hosted environment is the right choice.
## When to Use Modelcode Hosted
* Your project's dependencies are publicly accessible (npm, PyPI, Maven Central, Packagist, etc.)
* You want to get started quickly without installing anything on your own machine
* Your team does not have a stable, long-lived build server to run ModelDaemon on
* You prefer a fully managed, zero-maintenance build environment
For projects that depend on private services - such as internal APIs, private package registries, or databases not accessible from the public internet - choose [Self Hosted](/setup/build-environment/self-hosted-daemon) instead. With Self Hosted, you install **ModelDaemon** inside your own network so it inherits access to your private infrastructure directly.
## Enterprise Applications with Private Infrastructure
If your application needs private artifact repositories, complex network allowlists, or a site-to-site VPN to reach internal services, the standard hosted environment may not meet your requirements as it stands. supports enterprise configurations for exactly these cases, including:
* **Your own certificate authority.** A private root CA can be trusted inside the sandbox, so builds work behind a TLS-inspecting proxy without disabling verification.
* **Dedicated and isolated deployments**, including air-gapped installations.
* **Private build hosts** reached over mutually authenticated TLS.
If none of that is needed, the standard hosted environment is simpler and there is nothing to arrange.
Contact [support@modelcode.ai](mailto:support@modelcode.ai) to discuss your requirements. If you would rather keep everything inside your own network, [Self hosted](/setup/build-environment/self-hosted-daemon) is the other route to the same outcome.
# Self-hosted Daemon
Source: https://docs.modelcode.ai/setup/build-environment/self-hosted-daemon
Run the ModelDaemon inside your own network so projects that depend on private services work without recreating your environment
uses a **Self-hosted Daemon** (also called the **ModelDaemon**) to build, run, and test your application on your own infrastructure. You need it when your project depends on things the public internet cannot reach — internal APIs, databases, private package registries, licensed services.
If your project builds with publicly available dependencies, use [Modelcode Hosted](/setup/build-environment/modelcode-hosted) instead. There is nothing to install, and still [works out your lifecycle with you in chat](/setup/build-environment/lifecycle-setup).
## Designed for Real Environments
The ModelDaemon runs inside the environment your application already lives in — the same machine, the same network, the same credentials. There is no environment to recreate, nothing to containerize, and no infrastructure to replicate somewhere else.
That is the whole point. Enterprise applications depend on internal services, private registries, and configuration that is rarely documented well enough to reproduce faithfully. Rather than asking you to rebuild all of that in the cloud, comes to where it already works.
It does this without turning your machine into part of the project's runtime. Each job gets its own isolated workspace with its own dependencies, so does not install project runtimes onto your host or leave anything behind.
## Why This Approach Works
Recreating an enterprise application environment from scratch is harder than it looks. Internal services have specific versions, configurations, and network paths that are rarely fully documented. Private registries need credentials that may be tied to particular machines or users. Runtime behavior often depends on system configuration that was never committed to source control.
The daemon sidesteps all of it. The commands it runs are the commands your developers run. The network paths it uses are the paths your application uses. The credentials and config files are already in place.
You get the correctness of running in your real environment, without the operational cost of treating that environment as part of the project's stack.
## When to Use a Self-hosted Daemon
* Your application already builds and runs somewhere inside your network
* Its dependencies — runtimes, package managers, internal tools — are already in place
* That environment is stable and is not being decommissioned mid-project
* You want to be up and running without infrastructure changes
## How It Works
The daemon is a single program you run on a machine in your network. Once started, it:
1. **Connects to ** and reports that it is available
2. **Receives work** — project setup, milestone execution, code review, chat
3. **Runs each job in its own isolated workspace**, so jobs cannot interfere with one another
4. **Streams results and logs back**, then cleans the workspace up
Two properties of that design matter to most security reviews:
* **The daemon connects out; nothing connects in.** You do not open inbound ports or expose the machine.
* **Your source code stays on your machine.** The agent reads and writes it locally. coordinates the work but does not execute it, and your LLM provider keys never live on the host — that traffic is proxied through .
The daemon runs commands as the user that started it. It does not inherit your host's language runtimes, but it does inherit that user's network access, file permissions, and credentials — SSH keys, cloud CLI tokens, and so on. Run it as a user with the access your project needs, and nothing more.
## Pools: Capacity Belongs to the Team
Daemons are organized into **pools** — shared groups of machines that serve one or more projects.
This is what stops build capacity from belonging to one person. Any member of your organization with access to a project can run work on that project's pool, so most people never install anything. One person sets up the pool, and the team uses it.
* **Add a machine, add capacity.** routes each piece of work to an available machine on its own. You never assign jobs.
* **One pool can serve several projects**, so a single set of machines can back your whole modernization program.
* **Each pool declares its operating system up front**, so work only ever lands on a machine that can run it.
## Setting Up
The UI walks you through this — follow the on-screen steps.
**1. Choose your platform and hosting.** Build Environment setup asks two things: the **platform** your project runs on (Linux/macOS or Windows), and whether the project is **self hosted** or ** hosted**. Both are permanent for the life of the project — see [Switch between environments](/setup/build-environment/switching-environment).
**2. Join a pool, or create one.** The pool list shows each pool's platform, status, connected projects, and machine count.
If you are joining an existing pool, setup is finished here. If you are creating one, you name it and pick its operating system and architecture, and generates the exact install command for you.
**3. Install and verify.** Run the generated command on the machine, then click **Verify & Continue**.
Install the daemon on the **same machine or environment where your application runs**. That is what gives it access to your internal services and private registries. Installing it somewhere similar-looking is the most common cause of build failures that are hard to diagnose.
For everything the person running that command needs — network access, corporate certificates, registry mirrors, running it as a service, upgrades — see [Daemon Administration](/setup/build-environment/daemon-administration).
## After Setup
Once the daemon is connected, does the rest on its own:
1. **Works out what your project needs** by reading your codebase, and installs those dependencies in an isolated environment on the host.
2. **Discovers your lifecycle** — how to install, build, run, health-check, and test your application — and confirms it with you in Knowledge chat during the **Project Setup** stage. This is the same flow used for hosted projects.
3. **Shows you the result**, editable at any time under **Project Setup** in [Project Knowledge](/setup/build-environment/lifecycle-setup).
Secrets are encrypted in transit and at rest, and the daemon manages its own encryption keys — there is no key exchange for you to perform.
## Pool and Daemon Status
Each machine reports its status in real time. The project sidebar and Build Environment pages show the pool's health:
| Daemon status | Meaning | What to do |
| ------------- | -------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Available** | Connected and ready for work. | Nothing. |
| **Busy** | Running a job. | Other work routes to another machine in the pool, if one is free. |
| **Offline** | has not heard from it recently. | Check the machine is running and has network access. See [Daemon Administration](/setup/build-environment/daemon-administration#when-a-daemon-shows-as-offline). |
### Pool capacity
Each machine runs several pieces of work at once, and spreads work across the pool. When every machine is fully occupied, starting new milestone or ad-hoc work is refused rather than queued silently — you will see *"All workers in this project's pool are busy — try again when one frees up."* and can start it once a machine frees up.
**Knowledge chat** and **Code Review chat** are **exempt** from this. You can always open project knowledge or review code, even when every machine is running a milestone — the work that needs your attention is never gated behind the work that does not.
### Pool platform and architecture
Every pool has a **platform** — Linux or Windows — chosen when the pool is created and shown on the pool details page. Install each machine on that platform, and connect a project to a pool matching the project's own platform. Keeping them aligned is what lets generate commands in one shell and know they will run.
A machine installed on a different platform still registers and looks healthy, but no work routes to it. Check the pool's platform first if a new machine stays idle.
**Architecture is left open by default.** A pool takes ARM and Intel/AMD machines side by side, because dependencies are installed per host. You can set it when you create the pool, before any machine has registered, if you already know the pool must run on particular hardware.
To require one afterwards — for a project with prebuilt binaries, say — pin it from the pool details page. A pin is accepted while every machine already reports that architecture, and turns away other architectures from then on. Pinning never removes a machine that is already a member.
### Deleting a pool
A project stays on the pool it was set up with, so a pool can only be deleted once no projects are connected to it:
1. Check the pool details page for the projects connected to it.
2. Delete those projects, or keep the pool.
3. Delete the pool once no projects are listed.
Deleting a pool deregisters its machines and takes them offline. Removing machines from a pool does *not* delete the pool — uninstall them only when you want the hosts back.
### Daemon pool in the project sidebar
Once your project is connected, the Roadmap sidebar shows a **Daemon pool** section with:
* How many machines are online, out of the total registered
* **Active work** — what is running right now
* The pool's name, OS and architecture, and a **Manage** link
Expand **See daemon list** to see each machine and its live status.
## Environment Stability
The daemon is designed to run on a stable host. That environment should:
* Stay accessible for the duration of the project
* Behave consistently across sessions
* Not be decommissioned, re-imaged, or significantly reconfigured mid-project
This is a strength rather than a constraint. The daemon's reliability comes directly from the stability of the environment it runs in. Teams that treat their build environment as a managed, long-lived resource get the most consistent results.
## What a Typical Deployment Looks Like
1. The daemon is installed on the server or VM where the application already runs
2. It is pointed at with an API key
3. The agent discovers lifecycle commands from the codebase and confirms them with the team in chat
4. No infrastructure changes: no new VMs, no containers, no network changes
5. starts building and testing immediately, using the environment as it is
This is in production across applications with complex dependency chains, private Artifactory registries, and internal service dependencies. The common thread: the environment already worked, and the daemon used it directly.
## FAQ
### Does the ModelDaemon support Windows?
Yes, on Intel/AMD hardware — Windows 10/11 or Windows Server 2019+. Windows on ARM is not supported, and the installer stops before making any changes rather than half-installing.
### Do I need to install Python, Node, Java, or other runtimes on the host?
No. works out what each project needs and installs it into an isolated environment of its own. Your host only needs to reach the same network locations your application reaches.
### Where does the AI agent actually run?
On your machine, in a fresh isolated workspace per job, which is cleaned up afterwards. coordinates the work but does not execute it.
### Do you store my code or my LLM provider keys?
Your source code is read on your machine and is not copied off it as part of normal job execution. LLM calls are proxied through using your daemon's API key, so no provider keys (Anthropic, OpenAI, and so on) live on the host.
### Can I run multiple daemons on the same machine?
No — a second install replaces the first. To add capacity to a pool, install each daemon on a separate machine.
### Do I still need to write lifecycle commands by hand?
No. The agent works your lifecycle out with you in chat during **Project Setup**, then leaves it editable under **Project Setup** in [Project Knowledge](/setup/build-environment/lifecycle-setup).
### Do I need to upload an encryption key?
No. The daemon manages its own encryption keys.
## Next Steps
Install, network access, certificates, registries, upgrades, troubleshooting
How learns to build, run, and test your application
# Switch between environments
Source: https://docs.modelcode.ai/setup/build-environment/switching-environment
Why the build environment, daemon pool, and platform are permanent for a project
Three choices you make during Build Environment setup are permanent for the life of a project: **where it is hosted**, **which daemon pool it uses** if self hosted, and **which platform it runs on**.
They are permanent for the same underlying reason. From the moment a project is set up, everything that follows — how dependencies are installed, how scripts are written, how each milestone is built and validated — accumulates against those three choices. Changing one mid-project would mean re-deriving all of that work, and the failures that come out of a half-converted project are the hard kind: quiet, intermittent, and difficult to attribute.
So Modelcode treats these as foundational decisions rather than settings. **To move a project to a different environment, pool, or platform, create a new project with the setup you want.**
**Why hosting can't be switched**
Modelcode hosted and Self hosted resolve, install, and cache dependencies differently, and run your scripts differently. A project carries those conventions from the start.
**Why the daemon pool can't be switched**
When a project joins a pool, its dependencies are prepared on that pool's machines. Another pool's machines would need the same preparation before they could serve the project.
You *can* move an individual machine between pools — that is a separate operation, and a useful one if you are reorganizing capacity. What you cannot move is the project.
A pool also cannot be deleted while a project is connected to it. Deleting the project is what releases the pool.
**Why the platform can't be changed after setup**
A project's platform — Linux or Windows — is chosen at the same step, and it reaches further than the other two. It decides the shell every generated command is written in, the base image a sandbox is built from, and the syntax of the lifecycle scripts stored with the project. From the first milestone onward, that work accumulates in one dialect.
Pick the platform your application already builds on. A project that needs the other one is a new project.
# Collaborative Onboarding
Source: https://docs.modelcode.ai/setup/collaborative-onboarding
Hand over project setup to a teammate so multiple people can take turns during onboarding
Setting up a project often requires input from several people - someone who understands the build system, another who knows the business logic, and maybe a third who owns the test infrastructure. Collaborative onboarding lets your team take turns driving the setup, handing off control as needed without losing progress.
To keep the conversation with consistent and avoid conflicting edits, one person drives the onboarding at a time. That person can edit the Project Spec, chat with , and approve setup steps. Everyone else sees the project in read-only mode until control is handed to them.
## When to Use This
* **Domain handoff** - You have finished configuring the build environment but a teammate needs to review and refine the Project Spec sections related to their area of expertise.
* **Shift handoff** - Your workday is ending and a colleague in another timezone can continue the setup.
* **Specialist input** - The onboarding agent is asking questions about test infrastructure or CI pipelines that someone else on the team is better equipped to answer.
## Handing Over From the Roadmap
The **Getting Started** checklist on the Roadmap shows a **Hand over to teammate** link at the bottom.
## Handing Over From Knowledge Chat
Inside the Project Knowledge drawer, a bar appears above the chat input with the same **Hand over to teammate** link.
## The Handover Dialog
Clicking **Hand over to teammate** from either location opens the same dialog. It shows who is currently onboarding the project and lists your team members. Select a teammate, then click **Hand over**.
Once confirmed:
* The selected teammate receives an email notification
* They gain full control of the onboarding session
* Your view switches to read-only
If the agent is actively responding when you try to hand over, the dialog shows a notice asking you to wait until it finishes.
## Read-Only View
When another team member is onboarding the project, the Roadmap and Project Knowledge show a banner with their name and who assigned them.
You can still view the Project Spec, browse Knowledge chat history, and see progress on the Getting Started checklist. You cannot edit the spec, send chat messages, or approve steps until they hand over to you.
## Permissions
Handing over requires the **Project Update** permission. By default, Admin and Member roles have this permission. If your role does not include it, the handover option will not appear.
# GitHub Integration
Source: https://docs.modelcode.ai/setup/github-integration
Connect your GitHub account and manage repository access
Modelcode connects to your GitHub repositories through a **GitHub App**. This guide covers how the connection works and how to manage your repositories.
**GitHub Enterprise Server is not supported today.** Modelcode only works with
**GitHub.com** (cloud). Support for GitHub Enterprise Server (self-hosted) is
planned for **H2 2026**.
## Prerequisites
* A Modelcode account (sign up at [modelcode.ai](https://modelcode.ai))
* A GitHub account (personal or organization)
* At least one repository you want to work with
## How It Works
Modelcode uses two separate GitHub integrations:
1. **Sign-in with GitHub** — You can sign in to Modelcode using your GitHub account. This is handled through our identity provider and is used purely for authentication.
2. **GitHub App for repository access** — To access your repositories, you install the Modelcode GitHub App. This grants Modelcode read access to the repositories you select.
These are independent — signing in with GitHub does not automatically grant repository access. You must install the GitHub App separately.
## Signing In with GitHub
You can sign in to Modelcode with your GitHub account from the login page.
1. Go to [modelcode.ai](https://modelcode.ai)
2. On the login page, click **Continue with GitHub**
## Installing the GitHub App
### Step 1: Navigate to the Projects Page
1. Sign in to [modelcode.ai](https://modelcode.ai)
2. Go to the **Projects** page
3. If you haven't connected GitHub yet, you'll see a **Connect GitHub** button
### Step 2: Install the GitHub App
1. Click **Connect GitHub**
2. You'll be redirected to GitHub to install the Modelcode GitHub App
3. Choose which account or organization to install it on
4. Select which repositories Modelcode can access:
* **All repositories** - Grants access to every repo in your account or organization
* **Only select repositories** - Pick specific repos
We recommend selecting only the repositories you plan to work with. You can always add more later.
If you install the GitHub App on an organization, GitHub may require approval from an org owner before the installation completes.
### Step 3: Return to Modelcode
After installing the GitHub App on GitHub, you'll be redirected back to Modelcode and see a **Thank you for installing Morph!** confirmation. You can now create projects using your connected repositories.
If the redirect doesn't complete, check that your browser isn't blocking pop-ups or redirects from GitHub.
## Creating a Project with Connected Repositories
Once the GitHub App is installed:
1. Click **Create Project** on the Projects page
2. Enter a project name (auto-filled from your first repository name)
3. In the repository dropdown, select one repository
4. Confirm or change the **origin branch**
5. Set a **feature branch** name (prefixed with `morph-`)
6. Click **Create Project**
If you don't see a repository in the dropdown, click **Connect Repositories** at the bottom of the list to update your GitHub App installation and add more repos.
## Managing Repository Access
### Adding More Repositories
To grant Modelcode access to additional repositories:
1. From the **Projects** page or the **Create Project** modal, click **Connect Repositories**
2. You'll be taken to GitHub's app installation settings
3. Add the repositories you want
4. Return to Modelcode — the new repos will appear in the dropdown
Alternatively, go directly to GitHub:
1. Go to [GitHub Settings → Applications](https://github.com/settings/installations)
2. Find the **Modelcode** app
3. Click **Configure**
4. Add repositories to the selected list
### Removing Repository Access
To revoke access to specific repositories:
1. Go to [GitHub Settings → Applications](https://github.com/settings/installations)
2. Find the **Modelcode** app
3. Click **Configure**
4. Remove repositories from the selected list
### Uninstalling the GitHub App
To completely disconnect Modelcode from your GitHub account:
1. Go to [GitHub Settings → Applications](https://github.com/settings/installations)
2. Find the **Modelcode** app
3. Click **Uninstall**
Uninstalling the GitHub App does not delete any projects you've already created in Modelcode, but Modelcode will no longer be able to access your repositories.
## Troubleshooting
### "GitHub connection failed"
If the installation flow doesn't complete:
1. Ensure you're signed in to the correct GitHub account
2. Check that your browser allows redirects from github.com
3. Clear your browser cookies and try again
4. If using an organization, ensure you have permission to install GitHub Apps
### "Repository not showing up"
If you can't see a repository in the Create Project dropdown:
1. Click **Connect Repositories** in the dropdown to open your GitHub App settings
2. Verify the repository is in the selected list
3. Go to [GitHub Settings → Applications](https://github.com/settings/installations) and confirm Modelcode has access
4. Ensure the repository is included in your GitHub App installation
### "No Repositories Found"
If Modelcode says your GitHub is connected but no repositories are available:
1. Your GitHub App installation may not have any repositories selected
2. Click **Connect Repositories** to open the GitHub App configuration
3. Select the repositories you want to use
### "Insufficient permissions"
If you get a permissions error:
1. For organization repos, ensure an org admin has approved the GitHub App installation
2. Verify you have the necessary permissions on the repository in GitHub
3. Try clicking **Connect Repositories** to re-open the GitHub App configuration
### "Installation Failed" after returning from GitHub
If the post-install screen shows **Installation Failed**:
1. Go to [GitHub Settings -> Applications](https://github.com/settings/installations) and uninstall the **Modelcode** app
2. Return to Modelcode and start the installation again from the **Connect GitHub** button
### "Your GitHub connection is no longer active"
If you see this banner on the Projects page, your GitHub authorization has expired or been revoked:
1. Click **Reconnect GitHub** in the banner to re-run the OAuth and GitHub App flow
2. If the banner persists, confirm the **Modelcode** app is still installed at [GitHub Settings -> Applications](https://github.com/settings/installations)
## Next Steps
* [Quickstart](/quickstart) — Create your first migration project
* [Define Modernization Goals](/setup/modernization-goals) — Write effective goals for your migration
* [Reviewing the Project Spec](/setup/reviewing-project-spec) — Learn how to review and approve your migration plan
# GitLab Integration
Source: https://docs.modelcode.ai/setup/gitlab-integration
Connect your GitLab account and manage repository access
Modelcode connects to your GitLab repositories through **GitLab OAuth**. This guide covers how the connection works, how to manage your repositories, and how to configure publishing targets for your migration.
This page describes **GitLab.com** (SaaS), where Modelcode uses its own
pre-registered OAuth application. **Self-managed, self-hosted, and GitLab
Dedicated instances are also supported**, and they need a one-time setup where
you register an OAuth application in your own GitLab. See [Self-Managed
GitLab](/setup/gitlab-self-managed), then return here for project creation and
publishing.
## Prerequisites
* A Modelcode account (sign up at [modelcode.ai](https://modelcode.ai))
* A **GitLab.com** (SaaS) account. For a self-managed or Dedicated instance, complete [Self-Managed GitLab](/setup/gitlab-self-managed) first
* At least one repository you want to work with
## How It Works
Modelcode uses GitLab OAuth to authenticate and access your repositories:
1. **Sign in with GitLab** — You authenticate with your GitLab account on Modelcode's login page. This establishes your identity and grants Modelcode permission to access your repositories.
2. **Repository access** — Once signed in, Modelcode can list and read the repositories your GitLab account has access to. No separate app installation is required — your OAuth token provides access.
Unlike GitHub (which requires a separate GitHub App installation), GitLab access is granted in a single sign-in step through OAuth scopes.
On a self-managed instance the flow is identical from the user's side. The only difference is that an admin registers the OAuth application in your GitLab first, and users connect from the **Integrations** page rather than the login page. See [Self-Managed GitLab](/setup/gitlab-self-managed).
| | **GitHub** | **GitLab** |
| -------------- | ---------------------------------------------------------- | ------------------------------------------ |
| Sign-in | GitHub account via identity provider (authentication only) | GitLab OAuth (identity + repo access) |
| Repo access | Separate GitHub App installation | Included in OAuth sign-in |
| Publish target | GitHub account (installation) | GitLab principal (user, group, or project) |
GitLab’s consent screen lists the full set of permissions for the Morph OAuth
application (for example API access, repository read/write, OpenID Connect
profile and email, and registry access where applicable). These are required
so Modelcode can sign you in, list repositories, and push migration branches.
## Signing In with GitLab
### Step 1: Choose GitLab as Your Provider
1. Go to [modelcode.ai](https://modelcode.ai)
2. On the login page, click **Continue with GitLab**
You'll be redirected to GitLab's authorization page.
### Step 2: Authorize Modelcode
On GitLab, the OAuth application appears as **Morph** (the Modelcode integration).
1. Review the permissions Morph is requesting (API access, repository read/write, profile, and related scopes as shown)
2. Click **Authorize Morph** to grant access
3. You'll be redirected back to Modelcode
Once complete, you'll land on the **Projects** page with GitLab connected. Your OAuth token is securely stored and used for all subsequent GitLab operations.
## Creating a Project with GitLab Repositories
If you haven't connected GitLab yet, you'll see a **Connect GitLab** button on the Projects page.
Once GitLab is connected:
1. Click **Create Project** on the Projects page
2. Enter a project name (auto-filled from your first repository name)
3. In the repository dropdown, select one or more repositories from your GitLab account
4. For each repository, confirm or change the **origin branch**
5. Set a **feature branch** name (prefixed with `morph-`)
6. Click **Create Project**
Modelcode automatically resolves the GitLab principal (user, group, or project context) for each repository based on its namespace. No manual configuration is needed during project creation.
### If the Repository Dropdown Is Empty
If no repositories appear after connecting GitLab:
1. Verify your GitLab account has access to the repositories you expect
2. Check that the OAuth authorization was completed successfully
3. Try refreshing the page — the repository list is fetched from GitLab via Modelcode's backend
## Understanding GitLab Principals
When Modelcode publishes migration output (creates branches, pushes code) to GitLab, it uses a **principal** to determine credentials and permissions. A principal represents the GitLab entity that owns or manages the target repository.
### Principal Types
| Type | Description | Example |
| ----------- | ------------------------------ | ----------------------------- |
| **User** | A personal GitLab user account | `johndoe (user)` |
| **Group** | A GitLab group or subgroup | `my-org/backend-team (group)` |
| **Project** | A specific GitLab project | `my-org/my-repo (project)` |
Modelcode automatically infers the correct principal for each repository based on its namespace. In the approval UI, principals are displayed as `path (type)` — for example, `my-company/platform (group)`.
### How Principals Are Resolved
When you create a project or approve a migration plan, Modelcode resolves principals in the following order:
1. **Namespace match** — Matches the repository's GitLab namespace ID and kind (user or group)
2. **Declared user** — Matches an explicitly declared user principal on the repository
3. **Project ID** — Matches the GitLab project ID directly
4. **Group path** — Matches a group token whose path is a parent of the repository's namespace
In most cases, this resolution is automatic and requires no user input.
## Approving a Migration Plan
When reviewing and approving a migration plan for a GitLab project:
1. Open **Project Knowledge** from the **Roadmap** (**Modernization** → **Project Knowledge**) with **Project Spec** selected
2. Review the generated migration plan
3. For each new repository in the plan, a **GitLab principal** dropdown appears
4. Select the principal (user, group, or project) that should own the published repository
5. Click **Approve**
The principal dropdown is populated from your connected GitLab account. Modelcode combines principals from stored tokens and your repository list to provide all available options.
The **Approve** button remains disabled until every new repository has a
GitLab principal selected. If the dropdown is empty, see the troubleshooting
section below.
## Troubleshooting
### "No repositories found"
If Modelcode says GitLab is connected but no repositories are available:
1. Verify your GitLab account has access to the repositories you expect
2. The OAuth token may have expired - if you see a **Your GitLab connection is no longer active** banner on the Projects page, click **Reconnect GitLab**
3. Check that the repositories are not archived or restricted in GitLab
### "GitLab principal" dropdown is empty
If the principal dropdown shows no options when approving a migration plan:
1. Your GitLab OAuth session may have expired — refresh the page
2. If the issue persists, sign out and sign in again with GitLab to refresh the OAuth token
3. Verify that your GitLab account has the necessary permissions on the target group or project
Modelcode derives principals from both stored tokens and your repository list.
If your repository list loads successfully, principals should appear
automatically. An empty dropdown usually indicates an authentication issue.
### "Missing GitLab principal context"
If you see this error during project creation:
1. The repository metadata may be incomplete — close the modal, refresh the page, and try again
2. Reconnect GitLab by signing out and signing in again
3. Ensure your GitLab account has at least **Developer** access to the repository
### "Failed to load GitLab principal tokens"
This indicates a backend communication issue:
1. Refresh the page and try again
2. If the error persists, check your network connection
3. Contact support if the issue continues
### "We couldn't load GitLab accounts for publishing"
This message appears in the project overview when principals cannot be loaded:
1. Reconnect GitLab using the same flow as when you add a repository
2. Refresh the page after reconnecting
3. If you already use GitLab in this project, a simple page refresh may resolve the issue
## Next Steps
* [Self-Managed GitLab](/setup/gitlab-self-managed): Connect a self-hosted or GitLab Dedicated instance
* [Quickstart](/quickstart): Create your first migration project
* [Define Modernization Goals](/setup/modernization-goals): Write effective goals for your migration
* [Reviewing the Project Spec](/setup/reviewing-project-spec): Learn how to review and approve your migration plan
# Self-Managed GitLab
Source: https://docs.modelcode.ai/setup/gitlab-self-managed
Connect Modelcode to a self-hosted, self-managed, or GitLab Dedicated instance using your own OAuth application
Modelcode connects to **self-managed** (self-hosted) and **GitLab Dedicated** instances through an OAuth application that you create inside your own GitLab. You configure it once per organization on the **Integrations** page, and every user in your organization then signs in against your instance instead of GitLab.com.
This guide covers where to configure the integration in Modelcode, who in your organization needs to create the GitLab application, and the exact values you exchange between the two systems.
If your repositories are on **GitLab.com** (SaaS), no setup is required.
Modelcode ships with a pre-registered OAuth application. See [GitLab
Integration](/setup/gitlab-integration) instead.
## Prerequisites
* A Modelcode account with the **Admin** role (see [When the Integrations Page Is Visible](#when-the-integrations-page-is-visible))
* A GitLab instance reachable from Modelcode over HTTPS with a publicly valid TLS certificate
* Someone who can create an OAuth application in your GitLab, either an instance administrator or a group Owner (see [Who Can Create the Application](#who-can-create-the-application))
## How It Works
On GitLab.com, Modelcode uses its own OAuth application. On a self-managed instance that application does not exist, so **you register one in your GitLab and give Modelcode its credentials**.
| | **GitLab.com** | **Self-managed / Dedicated** |
| ----------------- | ------------------------------------------ | --------------------------------------------------------- |
| OAuth application | Pre-registered by Modelcode | You create it in your GitLab instance |
| Configuration | None | **Integrations** page: GitLab URL, Application ID, Secret |
| Who sets it up | Any user | A Modelcode admin plus a GitLab admin or group Owner |
| Sign-in | **Continue with GitLab** on the login page | **Connect GitLab** from the Integrations page |
The configuration is stored per organization. Once it is saved and connected, everyone in your Modelcode organization works against your instance.
## When the Integrations Page Is Visible
**Integrations** is where self-managed GitLab is configured. Three conditions must all be true for it to appear in the sidebar:
| Condition | Detail |
| ------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Enabled for your organization** | Modelcode turns Integrations on per organization. If it is missing entirely, email [support@modelcode.ai](mailto:support@modelcode.ai). |
| **Your role grants integration access** | The **Admin** role can view and edit integrations. The **Member** role cannot, so members never see the sidebar item. |
| **Your organization has something to configure** | Integrations is hidden once your organization is connected to a public cloud provider (GitLab.com, GitHub.com, or Azure DevOps Services) *and* has no custom configuration saved. It stays visible if you have not connected a repository yet, or if a custom configuration already exists. |
The second and third conditions are why a brand-new organization always sees
Integrations before it links its first repository. That is the window in which
you point Modelcode at your own GitLab instance.
If you have view access but not edit access, the page renders in read-only mode: the fields are visible but dimmed and disabled.
## Setup Overview
| Step | Where | Who |
| -------------------------------------- | ---------------------------- | ----------------------------------- |
| 1. Enter your GitLab URL | Modelcode → **Integrations** | Modelcode admin |
| 2. Copy the **OAuth Redirect URI** | Modelcode → **Integrations** | Modelcode admin |
| 3. Create the OAuth application | Your GitLab instance | GitLab administrator or group Owner |
| 4. Paste the Application ID and Secret | Modelcode → **Integrations** | Modelcode admin |
| 5. Authorize the application | Your GitLab consent screen | The connecting user |
## Step 1: Enter Your GitLab URL
1. In the Modelcode sidebar, click **Integrations**
2. Find the **GitLab** section. Its description reads *"Set the URL of your self-managed or Dedicated GitLab instance. Leave blank only for gitlab.com."*
3. In **GitLab URL**, enter the base web URL of your instance, for example `https://gitlab.example.com`
If GitLab is installed under a relative URL root, include that path, for example `https://example.com/gitlab`. A trailing slash is fine; Modelcode strips it.
The **OAuth Redirect URI** field and the application setup instructions appear
only after you enter a URL that is not `gitlab.com`. Fill in **GitLab URL**
first, because the rest of the form depends on it.
Once a custom URL is entered, the **GitLab** section expands to reveal the redirect URI, the required scopes, and the credential fields:
You do not need to configure an API URL or a clone host. Modelcode derives both
from **GitLab URL**. The API base becomes `/api/v4`.
## Step 2: Copy the OAuth Redirect URI
Once a custom GitLab URL is entered, Modelcode displays a read-only **OAuth Redirect URI** field with a copy button. Its hint reads *"Register this exact URI as the OAuth application's Redirect URI."*
The value takes this form:
```
https:///api/auth/gitlab-connect-complete
```
Copy it now. You will paste it into GitLab in the next step.
GitLab matches the redirect URI **exactly**. Do not add a trailing slash, change
the scheme, or register a shortened version. A mismatch fails the connection
with a token exchange error.
## Step 3: Create the OAuth Application in GitLab
### Who Can Create the Application
GitLab supports three kinds of OAuth application. They differ only by who owns them and who can create them.
| Application type | Created at | Required GitLab access | Use when |
| ----------------- | -------------------------------------------- | ----------------------- | ------------------------------------------------------------------------------------- |
| **Instance-wide** | **Admin** → **Applications** | Instance administrator | Recommended. One application serves every group and user on the instance. |
| **Group-owned** | Group → **Settings** → **Applications** | **Owner** of that group | You want the integration scoped to a single group and managed by that group's owners. |
| **User-owned** | Avatar → **Edit profile** → **Applications** | Any user | Trials and evaluations only. |
Avoid a **user-owned** application for production. It belongs to one person's
account. If that account is deactivated or removed, the application is deleted
and the integration stops working for your whole organization. Create the
application at the instance or group level instead.
### Create the Application
1. Sign in to your GitLab instance as an administrator (or as an Owner of the target group)
2. Go to the **Applications** page for the ownership level you chose above, then click **New application**
3. **Name**: use something recognizable to your users, such as `Modelcode`
4. **Redirect URI**: paste the **OAuth Redirect URI** you copied in Step 2
5. **Confidential**: leave this **checked**. Modelcode exchanges the authorization code server-side using the application secret.
6. **Trusted** (instance-wide applications only, optional): check this to skip the per-user consent screen for everyone on the instance
7. **Scopes**: enable exactly the scopes listed below
8. Click **Save application**
GitLab then displays the **Application ID** and **Secret**.
GitLab shows the **Secret** only once, on this confirmation screen. Copy it
before navigating away. If you lose it, rotate the secret in GitLab and paste
the new value into Modelcode.
### Required Scopes
Enable these seven scopes, and no others:
```
api read_user read_repository write_repository openid profile email
```
| Scope | Why Modelcode needs it |
| ---------------------------- | ----------------------------------------------------------------------------- |
| `api` | Read and manage projects, branches, and merge requests through the GitLab API |
| `read_user` | Identify the connecting user after authorization |
| `read_repository` | Clone and read repository contents during a migration |
| `write_repository` | Push migration branches back to your repositories |
| `openid`, `profile`, `email` | Establish the user's identity and email on sign-in |
Do not add `read_registry` or `write_registry`. Modelcode requests those against
GitLab.com only, and some self-managed versions reject them as unknown scopes.
## Step 4: Paste the Application ID and Secret
Back on the Modelcode **Integrations** page, in the **GitLab** section:
1. **Application ID**: paste the Application ID from GitLab (the field hint reads *"From GitLab → Applications."*)
2. **Secret**: paste the application secret
3. Click **Save & connect**
Modelcode saves the configuration, shows a **Saved** toast reading *"GitLab configuration saved."*, and immediately redirects you to your GitLab instance to authorize.
The **Secret** is write-only. After saving, the field shows a masked
`••••••••` placeholder and the stored value is never displayed again. Leaving it
blank on a later save keeps the existing secret; to rotate it, paste a new value
and save again.
If the button is disabled and its tooltip reads *"Enter the Application ID and Secret first."*, the credentials have not been saved yet.
## Step 5: Authorize the Application
On your GitLab instance, review the requested scopes and click **Authorize**. If an administrator marked the application as **Trusted**, this screen is skipped.
* **On success**, you land on the Modelcode **Projects** page with GitLab connected. Returning to **Integrations** shows a green **Configured** tag on the GitLab section.
* **On failure**, you return to **Integrations** with a **Connection failed** alert: *"GitLab rejected the connection (reason). Check the Application ID, Secret, and Redirect URI, then try again."*
Modelcode stores the OAuth token of the user who completes this authorization.
Repository visibility and push permissions follow **that user's** GitLab access.
Authorize with an account that has at least **Developer** access to every
repository you intend to migrate.
## Managing the Configuration
The **GitLab** section shows one of two status tags:
| Tag | Meaning |
| ------------------------------- | -------------------------------------------------------------------- |
| **Configured** (green) | Credentials are saved and the OAuth connection is live |
| **Saved, not connected** (gray) | Credentials are saved but no one has completed the authorization yet |
The primary button adapts to the current state:
| Button | When it appears |
| --------------------- | ------------------------------------------------------------------------------------ |
| **Save & connect** | You have unsaved edits |
| **Connect GitLab** | Credentials are saved but not yet connected |
| **Reconnect GitLab** | Already connected. Use this after rotating the secret or to refresh an expired token |
| **Reset to defaults** | A configuration exists |
**Reset to defaults** clears the saved GitLab URL and credentials for your whole
organization. Modelcode reverts to its GitLab.com defaults, and existing
connections to your instance stop resolving. Use it only when you are
deliberately decommissioning the integration.
## Network Requirements
The integration requires traffic in both directions.
| Direction | Endpoints | Purpose |
| --------------------------- | ------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| **Modelcode → your GitLab** | `https:///oauth/token`, `https:///api/v4` | Exchange and refresh OAuth tokens; read repositories; create branches and merge requests |
| **Your GitLab → Modelcode** | `https://callback.modelcode.ai/gitlab/webhook` | Deliver project webhooks back to Modelcode |
| **User's browser → both** | Your GitLab and Modelcode | Complete the OAuth authorization redirect |
Your instance must present a publicly valid TLS certificate. Modelcode does not
support custom or private certificate authorities. If your GitLab is only
reachable inside a private network, contact
[support@modelcode.ai](mailto:support@modelcode.ai) to discuss deployment
options.
## Troubleshooting
### Integrations is missing from the sidebar
Check each condition in [When the Integrations Page Is Visible](#when-the-integrations-page-is-visible): the feature must be enabled for your organization, your role must be **Admin**, and your organization must not already be connected to a public cloud provider with no custom configuration.
### The OAuth Redirect URI field never appears
The field is shown only for a custom host. Confirm **GitLab URL** is filled in and is not `gitlab.com`.
### Modelcode rejects your Application ID on gitlab.com
You entered an **Application ID** and **Secret** while **GitLab URL** is still `gitlab.com` (or blank). On GitLab.com, Modelcode always uses its own application. Either set your self-managed URL or clear the credentials.
### Connection failed — your credentials were not saved (`not_configured`)
The Application ID was not saved. Re-enter the **Application ID** and **Secret**, then click **Save & connect**.
### Connection failed — GitLab refused the credentials (`token_exchange_failed`)
The most common causes, in order:
1. The **Redirect URI** registered in GitLab does not exactly match the one shown in Modelcode
2. The **Secret** is wrong or was rotated in GitLab without being updated in Modelcode
3. Modelcode cannot reach `https:///oauth/token`, so check egress and TLS
### Connection failed — the authorization took too long (`invalid_state`, `expired_state`, `session_expired`)
The authorization took longer than 10 minutes, or your Modelcode session expired mid-flow. Return to **Integrations** and click **Connect GitLab** again.
### Connection failed — the GitLab URL changed mid-flow (`host_mismatch`)
The **GitLab URL** changed between starting and completing the authorization. Refresh **Integrations** and retry.
### Connection failed — Modelcode could not read your GitLab profile (`gitlab_user_fetch_failed`)
Modelcode authorized successfully but could not read the user profile from `https:///api/v4`. Verify the API is reachable from Modelcode and that the application includes the `read_user` scope.
### Connection failed — your organization uses a different git provider (`provider_mismatch`)
Your organization is locked to a different git provider. Contact [support@modelcode.ai](mailto:support@modelcode.ai) to change it.
### No repositories appear after connecting
Repository access follows the GitLab account that completed the authorization. Verify that account can see the repositories in GitLab, then click **Reconnect GitLab** to refresh the token.
## Next Steps
* [GitLab Integration](/setup/gitlab-integration): Create projects, understand GitLab principals, and approve migration plans
* [Quickstart](/quickstart): Create your first migration project
* [Define Modernization Goals](/setup/modernization-goals): Write effective goals for your migration
# Defining Modernization Goals
Source: https://docs.modelcode.ai/setup/modernization-goals
How to describe what you want to achieve with your migration
Modernization goals are your starting point. They tell what you want to accomplish, and everything else - the Project Spec, milestones, and the full roadmap - flows from this input.
is optimized for modernizing large codebases with 20,000 or more lines of code.
## Why This Matters
Your modernization goals become the foundation for the entire migration. uses them to:
* Analyze which parts of your repositories are relevant
* Determine the target technology stack
* Generate your Project Spec
* Plan the milestone sequence
Vague goals produce vague results. Specific goals produce a focused, actionable plan.
## Writing Effective Goals
### Be Specific About Technologies
Instead of general statements, name the specific technologies:
| Less Effective | More Effective |
| ----------------------- | ---------------------------------------------------- |
| "Modernize the backend" | "Migrate from Express.js to FastAPI" |
| "Update Python" | "Upgrade from Python 2.7 to Python 3.12" |
| "Use a modern frontend" | "Migrate from AngularJS to React 18 with TypeScript" |
### State the Transformation
Describe both where you're coming from and where you're going:
* "Translate the source code from **Ada** to **C++**"
* "Upgrade **Java 8 with Spring Boot 2** to **Java 21 with Spring Boot 3**"
* "Migrate from **jQuery** to **vanilla JavaScript ES2022**"
### Include Version Numbers When Relevant
Version specificity helps make the right choices:
* "Upgrade to **Python 3.12**" (not just "Python 3")
* "Use **React 18** with hooks" (not just "React")
* "Target **Java 21** LTS" (not just "latest Java")
## Using Advanced Options
Click **Advanced Options** to access additional fields.
### Additional Instructions
Use this for requirements that don't fit in the main goal:
**Examples:**
* "Use pytest for all tests with 80% coverage target"
* "Apply the repository pattern for database access"
* "Use our company's standard logging format"
* "Prefer functional components over class components"
* "Keep the existing API contracts unchanged"
This is where you encode specific technical decisions or constraints.
### Modernization Scope
By default, migrates all repositories in the project. Use this field to focus on specific parts:
**Examples:**
* `src/backend/` - Only migrate the backend folder
* `packages/core/` - Focus on a specific package
* `src/legacy-module/` - Target a legacy module
Leave empty to migrate everything. If your project includes multiple repositories, each repo's role (Modified, New, Reference Only, 1-to-1 Migration) is configured in the Project Overview as part of the Project Spec flow.
## Example Goals
### Language Translation
```
Translate the source code from Ada to C++
```
**Additional Instructions:**
```
- Use modern C++20 features where appropriate
- Maintain the same module structure
- Generate CMake build configuration
```
### Framework Migration
```
Migrate from AngularJS to React with TypeScript
```
**Additional Instructions:**
```
- Use functional components with hooks
- Implement state management with React Context
- Use CSS Modules for styling
- Maintain the same routing structure
```
### Language Upgrade
```
Upgrade Python 2.7 to Python 3.12
```
**Additional Instructions:**
```
- Use type hints throughout
- Replace deprecated libraries with modern equivalents
- Use pathlib instead of os.path
- Maintain backward compatibility for the public API
```
### Architecture Change
```
Refactor the monolithic application to use a service-oriented architecture
```
**Additional Instructions:**
```
- Create separate services for user management, orders, and inventory
- Use REST APIs for inter-service communication
- Implement shared types in a common package
- Generate Docker configurations for each service
```
## What Happens Next
After you click **Continue**, starts generating your **Project Spec** - goals, scope, and approach for your migration, including the Project Overview describing your repositories and their roles.
[**Project Knowledge**](/customization/project-knowledge) opens automatically on the Roadmap so you can review and approve the spec (with chat) before any migration begins. The spec is generated in the background and appears in the drawer shortly after. See [Reviewing the Project Spec](/setup/reviewing-project-spec) for details.
# Reviewing the Project Spec
Source: https://docs.modelcode.ai/setup/reviewing-project-spec
Read, refine, and approve your Project Spec using the Project Knowledge drawer and Knowledge chat
The **Project Spec** is the detailed document for your migration. It describes exactly how will transform your code across the repositories in your project. This page is about **that document** — how to review it, refine it with chat, and approve it.
You do that work inside the **Project Knowledge** drawer on the **Roadmap**. The first time generates your Project Spec, that drawer opens automatically so you can review the spec. Select **Project Spec** in the tree, use **Knowledge chat** to interact with , and approve when you are ready. Any time after that, go to the **Roadmap** and under **Modernization** click **Project Knowledge** to open the same drawer.
For wikis, rules, milestones in that drawer, diffs, and imports, see [Project Knowledge](/customization/project-knowledge).
Take the time to review the Project Spec carefully before approving. You can still refine it with Knowledge chat after approval — if milestone planning has already run, edits apply to future milestones only.
emails you when the spec is ready, so you don't have to watch for it:
## Reviewing the Project Spec
After you submit your Modernization Goals, automatically generates the Project Spec. **Project Knowledge** opens the first time it is ready. To review:
1. Confirm **Project Spec** is selected in the tree (it usually is on first open)
2. Read the generated content and check that it captures your intent
3. Use **Knowledge chat** to ask questions, drill into sections, or request clarifications
**Later visits:** On the **Roadmap**, open **Project Knowledge** (**Modernization**), then select **Project Spec** in the tree.
Once the Project Spec is ready, the **Roadmap** also surfaces a **Next Step** box at the top of the Getting Started checklist — "Approve your project spec to start planning your roadmap." with an **Approve Project Spec** button. Clicking that button opens the Project Knowledge drawer directly on the Project Spec, so you don't have to navigate through the tree yourself.
While the spec is still generating you'll see the same box in a loading state ("Generating Project Spec…"); it switches to the actionable Next Step automatically once the spec is ready.
### What to Look For
* **Target stack** — Are the destination technologies correct?
* **Migration approach** — Does the planned transformation make sense?
* **Requirements** — Are all your constraints captured?
* **Scope** — Is it migrating the right parts of your codebase?
## Refining the Project Spec
If something needs adjustment, use **Knowledge chat** in the Project Knowledge drawer. Describe what should change—for example:
```
Add a requirement that all new APIs must return JSON and use
RFC 7807 problem details for errors.
```
```
The spec says we're moving to FastAPI, but we want Starlette
with Jinja2 templates for the admin UI only—please update that.
```
### What You Might Ask For
* Missing requirements or constraints
* Clearer wording on ambiguous sections
* Preferred libraries or patterns
* Scope corrections (include or exclude parts of the codebase)
* Constraints (e.g., "maintain backward compatibility")
### Iterating with
When the Project Spec has been updated, you can click **Auto-review** to have compare the latest version against the codebase analysis and your original intent. It may suggest:
* Clarifications for ambiguous statements
* Missing details that could cause issues
* Potential conflicts or inconsistencies
For each recommendation, you can **Accept** or **Reject** it. You must resolve all recommendations before approving.
## Approving the Project Spec
When you're satisfied with the Project Spec:
1. Resolve **Auto-review** recommendations (if any)
2. Click **Approve** in the Project Knowledge drawer
3. Confirm the approval
After approval, immediately begins planning your migration roadmap.
## What Happens After Approval
The approved Project Spec triggers **Roadmap Generation** — plans a sequence of milestones based on your Project Spec, the codebase analysis, and the project overview.
See [Milestones](/migration/milestones-and-tasks) for details on how the roadmap executes.
## Best Practices
### Be Explicit About Preferences
Don't assume will guess your preferences. If you want:
* A specific testing framework → say so
* A particular folder structure → specify it
* Certain naming conventions → include them
### Consider Edge Cases
Think about areas where defaults might not work:
* Configuration files that need special handling
* Environment-specific code
* Integration points with external systems
### Review with Your Team
If others will work with the migrated code, consider having them review the Project Spec before approval. They may catch requirements you missed. You can [hand over onboarding](/setup/collaborative-onboarding) to a teammate so they can review and refine the spec directly.
## Troubleshooting
### "I approved but now I need changes"
You can still adjust an approved Project Spec. Open **Project Knowledge** from the **Roadmap** and use **Knowledge chat** to describe the change, the same way you refined it before approval. If milestone planning has already run, spec changes are reflected in future milestones only — already-completed milestones are not rewritten. The source repositories selected at project creation cannot be changed.
For milestone-level changes, see [Editing Milestones](/customization/editing-milestones); for conventions you want enforced on future work, use [Rules](/customization/rules).
### "The **Auto-review** recommendations don't make sense"
Recommendations are suggestions, not requirements. If a recommendation doesn't apply to your situation, click **Reject** and proceed.
### "The Project Spec doesn't match my goal"
If the generated Project Spec significantly misses your intent:
1. Use **Knowledge chat** in Project Knowledge to correct the misunderstanding and ask for updates
2. Use **Auto-review** to validate after changes
3. Approve only when satisfied
# Amazon Cognito
Source: https://docs.modelcode.ai/setup/sso/cognito
Configure Amazon Cognito as an OpenID Connect identity provider for Modelcode
This guide walks through configuring **Amazon Cognito** as an OIDC identity provider for Modelcode SSO. Cognito User Pools natively support OpenID Connect.
## Prerequisites
* Admin access to your Modelcode organization, **signed in with email and password** — the SSO settings page is not available to users who signed in with a social provider (GitHub, GitLab, Microsoft)
* An AWS account with access to Amazon Cognito
* Privileges to create and edit app clients and policies in your Cognito User Pool
## Step 1: Create an App Client in Cognito
1. In the AWS Console, navigate to **Amazon Cognito → User Pools**
2. Select your User Pool (or create a new one)
3. Go to **App integration → App clients and analytics**
4. Click **Create app client**
5. Configure the app client:
| Field | Value |
| ---------------------------- | ----------------------------------------- |
| **App type** | Confidential client |
| **App client name** | `Modelcode SSO` (or any descriptive name) |
| **Generate a client secret** | Yes |
6. Under **Hosted UI settings**, configure:
| Field | Value |
| ------------------------- | ---------------------------------------------------------------------------------------------------- |
| **Allowed callback URLs** | The **Callback URL** from the Modelcode SSO settings page (displayed when you select OpenID Connect) |
| **Allowed sign-out URLs** | `https://morph.modelcode.ai` (optional) |
| **Identity providers** | Select the providers enabled in your User Pool |
| **OAuth 2.0 grant types** | Authorization code grant |
| **OpenID Connect scopes** | `openid`, `email`, `profile` |
The Callback URL is displayed on the Modelcode SSO settings page when you select OpenID Connect.
7. Click **Create app client**
8. After creation, note the **Client ID** and **Client Secret** from the app client details
## Step 2: Find Your Cognito Issuer URL
The Cognito Issuer URL follows this format:
```
https://cognito-idp..amazonaws.com/
```
To find your values:
1. In the Cognito console, go to your User Pool
2. The **User Pool ID** is displayed on the overview page (e.g., `us-east-1_aBcDeFgHi`)
3. The **Region** is the AWS region where your User Pool is hosted (e.g., `us-east-1`)
For example, if your User Pool ID is `us-east-1_aBcDeFgHi`, the Issuer URL is:
```
https://cognito-idp.us-east-1.amazonaws.com/us-east-1_aBcDeFgHi
```
You can verify the discovery document is available by visiting:
```
https://cognito-idp..amazonaws.com//.well-known/openid-configuration
```
## Step 3: Configure OIDC in Modelcode
1. In Modelcode, navigate to **Single Sign-On** in the sidebar
2. Click **Setup SSO** (or **Edit** if updating)
3. Select **OpenID Connect** as the protocol
4. Enter the following:
| Field | Value |
| ----------------- | ----------------------------------------------------------- |
| **Issuer URL** | `https://cognito-idp..amazonaws.com/` |
| **Client ID** | The Client ID from your Cognito app client |
| **Client Secret** | The Client Secret from your Cognito app client |
| **Scopes** | `openid email profile` (default) |
5. Click **Verify & Save**
Modelcode validates the configuration by fetching the Cognito OIDC discovery document.
## Step 4: Update the Callback URL in Cognito
After configuring, verify the **Callback URL** displayed on the Modelcode SSO settings page matches the **Allowed callback URL** in your Cognito app client. Update the Cognito app client if needed.
## Step 5: Invite Users and Share the Portal Link
Before users can sign in via SSO, they must be invited to Modelcode:
1. In Modelcode, go to the [Members](https://morph.modelcode.ai/user-roles?tab=users) page and invite each user who needs SSO access
2. Copy the **Portal Link** from the SSO settings page and share it with your team:
```
https://morph.modelcode.ai/sso-portal/
```
When team members visit this link, they are redirected to the Cognito hosted UI (or your custom UI domain) to sign in, then returned to Modelcode with an active session.
## Troubleshooting
### "Verification failed" during setup
* Confirm the Issuer URL follows the format `https://cognito-idp..amazonaws.com/`
* Verify the User Pool ID and region are correct
* Access the discovery URL in your browser to confirm it returns a JSON document
### Users see "redirect\_mismatch" error
* The Callback URL in Cognito must exactly match the Callback URL shown in Modelcode — including the protocol, domain, and path
* Check for trailing slashes or other differences
### Users authenticate but are not recognized in Modelcode
* Ensure the user's email in Cognito matches their Modelcode account email
* Verify the `email` attribute is configured and populated for users in the Cognito User Pool
* Confirm the `email` scope is included in the app client's allowed scopes
* Ensure users are accessing Modelcode through the **Portal Link**, not the standard login page
### Users see the Cognito hosted UI instead of a custom login page
* If you've configured a custom domain for your Cognito User Pool, it should work automatically with OIDC
* The Cognito hosted UI is the default authentication interface when no custom UI is configured
# OpenID Connect (OIDC)
Source: https://docs.modelcode.ai/setup/sso/oidc
Configure Single Sign-On with any OpenID Connect identity provider
OpenID Connect (OIDC) is the recommended protocol for connecting modern identity providers to Modelcode. Any provider that publishes a `/.well-known/openid-configuration` discovery document is compatible.
## Prerequisites
* Admin access to your Modelcode organization, **signed in with email and password** — the SSO settings page is not available to users who signed in with a social provider (GitHub, GitLab, Microsoft)
* An identity provider that supports OpenID Connect (e.g., GitLab, Azure AD, Auth0, Amazon Cognito, Google Workspace)
* Privileges in your identity provider to create and edit applications and policies
## Step 1: Create an Application in Your Identity Provider
In your identity provider, create a new OIDC application (sometimes called an "OAuth app" or "client"). You will need the following from Modelcode to complete the setup:
| Field | Description |
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| **Callback URL** | The redirect URI Modelcode uses to complete authentication. Displayed on the SSO settings page when you select OpenID Connect. |
Configure the application in your identity provider with the following settings:
* **Grant type**: Authorization Code
* **Scopes**: `openid`, `email`, `profile` (at minimum)
* **Redirect URI**: The Callback URL from Modelcode
Once created, your identity provider will give you:
* **Issuer URL** — The base URL of your OIDC provider (e.g., `https://accounts.google.com` or `https://gitlab.com`)
* **Client ID** — The public identifier for the application
* **Client Secret** — The secret used to authenticate the application
## Step 2: Configure OIDC in Modelcode
1. In Modelcode, navigate to **Single Sign-On** in the sidebar
2. Click **Setup SSO** (or **Edit** if updating an existing configuration)
3. Select **OpenID Connect** as the protocol
4. Enter the following:
| Field | Required | Description |
| ----------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Issuer URL** | Yes | The base URL of your OIDC provider. Modelcode appends `/.well-known/openid-configuration` automatically — you can paste either the bare issuer or the full discovery URL. |
| **Client ID** | Yes | The client identifier from your identity provider. |
| **Client Secret** | Yes (first setup) | The client secret from your identity provider. On subsequent edits, this field is masked; leave it unchanged to keep the existing secret. |
| **Scopes** | No | Defaults to `openid email profile`. Only change this if your provider requires additional scopes. |
5. Click **Verify & Save**
Modelcode fetches the OIDC discovery document and validates that the required endpoints (`authorization_endpoint`, `token_endpoint`, `jwks_uri`) are present. If you entered a new Client ID and Secret, Modelcode also probes the token endpoint to verify the credentials are accepted.
Some identity providers do not support the client-credentials grant used for verification. In that case, the probe result is "inconclusive" and the configuration is saved normally. If the probe detects the credentials are definitively rejected, you'll see a warning — but you can still choose **Save Anyway** if you believe the credentials are correct.
## Step 3: Invite Users and Share the Portal Link
Before users can sign in via SSO, they must be invited to Modelcode:
1. Go to the [Members](https://morph.modelcode.ai/user-roles?tab=users) page in Modelcode and invite each user who needs SSO access
2. Copy the **Portal Link** from the Single Sign-On settings page and share it with your team:
```
https://morph.modelcode.ai/sso-portal/
```
## Supported OIDC Providers
Any provider with a valid OIDC discovery document works with Modelcode. Common providers include:
* **Okta** — See the [Okta guide](/setup/sso/okta) for step-by-step instructions
* **Amazon Cognito** — See the [Cognito guide](/setup/sso/cognito) for step-by-step instructions
* **Azure AD / Microsoft Entra ID**
* **Auth0**
* **Google Workspace**
* **GitLab**
* **OneLogin**
## Troubleshooting
### "Verification failed" when saving
* Confirm the **Issuer URL** is correct and uses HTTPS
* Verify the URL is publicly reachable (not behind a VPN or firewall)
* Check that the `/.well-known/openid-configuration` endpoint returns a valid JSON document with `issuer`, `authorization_endpoint`, `token_endpoint`, and `jwks_uri`
### Users see "SSO Not Found" on the portal page
* The SSO configuration may have been removed. Check the **Single Sign-On** settings page to confirm it's still active
* Verify the Portal Link URL is correct
### Users can't sign in after SSO is configured
* Ensure the **Callback URL** from Modelcode is registered as a valid redirect URI in your identity provider
* Confirm the **Client ID** and **Client Secret** are correct
* Check that the application in your identity provider is active and not disabled
* Verify the required scopes (`openid`, `email`, `profile`) are allowed for the application
* Users must be invited to the organization before they can sign in via SSO — SSO does not allow self-registration
* The user's email in the identity provider must be verified — unverified emails are rejected
# Okta
Source: https://docs.modelcode.ai/setup/sso/okta
Configure Okta as an identity provider for Modelcode using SAML 2.0 or OpenID Connect
This guide walks through configuring **Okta** as an identity provider for Modelcode SSO. Okta supports both SAML 2.0 and OpenID Connect — choose the protocol that best fits your setup.
**We recommend SAML 2.0 for Okta.** It's typically quicker to configure and doesn't require managing authorization server access policies.
## Prerequisites
* Admin access to your Modelcode organization, **signed in with email and password** — the SSO settings page is not available to users who signed in with a social provider (GitHub, GitLab, Microsoft)
* An Okta admin account with privileges to create and edit applications and policies
***
## SAML 2.0
### Step 1: Get Modelcode's Service Provider Details
Before creating the Okta application, get the SP details from Modelcode:
1. In Modelcode, navigate to **Single Sign-On** in the sidebar
2. Click **Setup SSO** and select **SAML 2.0**
3. Copy the **ACS URL** and **SP Entity ID** displayed on the form
### Step 2: Create a SAML Application in Okta
1. In the Okta Admin Console, go to **Applications → Applications**
2. Click **Create App Integration**
3. Select **SAML 2.0** and click **Next**
#### General Settings
| Field | Value |
| ------------ | ------------------------------------- |
| **App name** | `Modelcode` (or any descriptive name) |
| **App logo** | Optional |
Click **Next**.
#### SAML Settings
| Field | Value |
| -------------------------------------------------- | ----------------------------------------- |
| **Single sign-on URL** | Paste the **ACS URL** from Modelcode |
| **Use this for Recipient URL and Destination URL** | Yes (checked) |
| **Audience URI (SP Entity ID)** | Paste the **SP Entity ID** from Modelcode |
| **Name ID format** | `EmailAddress` |
| **Application username** | `Email` |
Leave other fields at their defaults and click **Next**.
#### Feedback
Select **I'm an Okta customer adding an internal app** and click **Finish**.
#### Attribute Statements
After the application is created, go to the **Sign On** tab and add the following attribute statements so Modelcode receives the user's profile information in the SAML assertion:
| Name | Value |
| ----------- | ------------------------ |
| `email` | `user.profile.email` |
| `firstName` | `user.profile.firstName` |
| `lastName` | `user.profile.lastName` |
### Step 3: Get Okta's Identity Provider Details
After creating the application:
1. Go to the **Sign On** tab of your new Okta application
2. Find the **Metadata URL** — this is typically labeled "Metadata URL" or available via a link like "Identity Provider metadata"
3. Copy the **Metadata URL**
Alternatively, if you prefer manual configuration, find these values on the Sign On tab:
| Okta Field | Modelcode Field |
| ---------------------------------------- | -------------------------------------------------------- |
| **Sign on URL** or **SAML 2.0 Endpoint** | SSO URL |
| **Issuer** | Entity ID |
| **Signing Certificate** | Signing Certificate (download and paste the PEM content) |
### Step 4: Configure SAML in Modelcode
1. In Modelcode, navigate to **Single Sign-On** in the sidebar
2. Click **Setup SSO** (or **Edit** if updating)
3. Select **SAML 2.0** as the protocol
4. Choose your configuration method:
Paste the **Metadata URL** from Okta. Modelcode automatically extracts all required IdP details.
Click **Configure manually** and enter:
| Field | Value |
| ----------------------- | ------------------------------------------- |
| **SSO URL** | The Sign on URL from Okta |
| **Entity ID** | The Issuer from Okta |
| **Signing Certificate** | The X.509 certificate content in PEM format |
5. Click **Verify & Save**
### Step 5: Assign Users and Share the Portal Link
1. In Okta, go to your Modelcode application's **Assignments** tab
2. Assign individual users or groups
3. In Modelcode, go to the [Members](https://morph.modelcode.ai/user-roles?tab=users) page and invite each user who needs SSO access — users cannot sign in via SSO until they have been invited
4. Copy the **Portal Link** from the SSO settings page and share it with your team:
```
https://morph.modelcode.ai/sso-portal/
```
***
## OpenID Connect
### Step 1: Create a Web Application in Okta
1. In the Okta Admin Console, go to **Applications → Applications**
2. Click **Create App Integration**
3. Select **OIDC - OpenID Connect** as the sign-in method
4. Select **Web Application** as the application type
5. Click **Next**
#### General Settings
| Field | Value |
| -------------------------- | --------------------------------------------------------- |
| **App integration name** | `Modelcode` (or any descriptive name) |
| **Grant type** | Authorization Code (default) |
| **Sign-in redirect URIs** | The **Callback URL** from the Modelcode SSO settings page |
| **Sign-out redirect URIs** | Optional |
6. Click **Save**
After saving, Okta displays the **Client ID** and **Client Secret** on the application's **General** tab. Copy both values — you'll need them in the next step.
Copy the Client Secret immediately. Depending on your Okta configuration, the secret may only be visible once.
### Step 2: Find Your Issuer URL
The Issuer URL tells Modelcode where to find Okta's OIDC discovery document.
1. In the Okta Admin Console, navigate to **Security → API** in the left sidebar
2. Click on the **Authorization Servers** tab
3. Click on your authorization server (usually named **default**)
4. Under the **Settings** tab, find the **Issuer** field
5. Copy the Issuer URL
Your Issuer URL will look like:
```
https://.okta.com/oauth2/default
```
### Step 3: Add an Access Policy
Your Okta authorization server must have an access policy that allows your Modelcode application to request tokens. Without a policy (or a matching rule), Okta rejects the login attempt.
1. In the Okta Admin Console, navigate to **Security → API**
2. Click on your authorization server (e.g., **default**)
3. Select the **Access Policies** tab
4. If no policy exists, click **Add Policy**:
* **Name**: `Modelcode SSO` (or any descriptive name)
* **Assign to**: **All clients**, or select **The following clients** and enter your Modelcode application name
* Click **Create Policy**
5. Inside the policy, click **Add Rule**:
* **Name**: `Allow login` (or any descriptive name)
* **Grant type**: Ensure **Authorization Code** is selected
* Leave other fields at their defaults
* Click **Create Rule**
If your authorization server already has a policy that covers all clients or includes your Modelcode application, you can skip this step.
### Step 4: Configure OIDC in Modelcode
1. In Modelcode, navigate to **Single Sign-On** in the sidebar
2. Click **Setup SSO** (or **Edit** if updating)
3. Select **OpenID Connect** as the protocol
4. Enter the following:
| Field | Value |
| ----------------- | -------------------------------------------------------------------------------- |
| **Issuer URL** | The Issuer URL from Okta (e.g., `https://.okta.com/oauth2/default`) |
| **Client ID** | The Client ID from your Okta application |
| **Client Secret** | The Client Secret from your Okta application |
| **Scopes** | `openid email profile` (default) |
5. Click **Verify & Save**
Modelcode validates the connection by fetching the OIDC discovery document and optionally verifying the client credentials.
### Step 5: Assign Users and Share the Portal Link
1. In Okta, go to your Modelcode application's **Assignments** tab
2. Assign individual users or groups
3. In Modelcode, go to the [Members](https://morph.modelcode.ai/user-roles?tab=users) page and invite each user who needs SSO access — users cannot sign in via SSO until they have been invited
4. Copy the **Portal Link** from the SSO settings page and share it with your team:
```
https://morph.modelcode.ai/sso-portal/
```
***
## Troubleshooting
### SAML: "Verification failed" when saving the Metadata URL
* Confirm the Metadata URL uses HTTPS and is publicly reachable
* Try accessing the Metadata URL in your browser to verify it returns XML
* If the URL is behind a firewall, use manual configuration instead
### SAML: Users see a SAML error after authenticating
* Verify the **Single sign-on URL** in Okta matches the ACS URL from Modelcode exactly
* Confirm the **Audience URI** in Okta matches the SP Entity ID from Modelcode exactly
* Check that **Name ID format** is set to `EmailAddress`
* Ensure the user is assigned to the application in Okta
### SAML: Certificate rotation
When Okta rotates signing certificates:
* If using **Metadata URL**: Modelcode fetches the latest metadata on each authentication attempt, so certificate rotation is handled automatically
* If using **manual configuration**: Update the signing certificate in the Modelcode SSO settings after Okta rotates
### OIDC: "Verification failed" when saving
* Confirm the **Issuer URL** matches the Issuer field from your Okta authorization server
* Verify the URL uses HTTPS and is publicly reachable
* Check that the authorization server is active in Okta
### OIDC: Users see an error after authenticating
* Verify the **Sign-in redirect URI** in Okta matches the Callback URL from Modelcode exactly
* Confirm the application type is **Web Application** (not SPA or Native)
* Check that the **Grant type** includes Authorization Code
* Ensure the authorization server has an access policy that covers your application
* Ensure the user is assigned to the application in Okta
### Users authenticate but are not recognized in Modelcode
* The user's email in Okta must match their Modelcode account email
* Ensure users are accessing Modelcode through the **Portal Link**, not the standard login page
* If the user hasn't been invited to the organization yet, the admin must send an invitation first
# SAML 2.0
Source: https://docs.modelcode.ai/setup/sso/saml
Configure Single Sign-On with any SAML 2.0 identity provider
SAML 2.0 is widely supported by enterprise identity providers. Modelcode acts as the **Service Provider (SP)**, and your identity provider acts as the **Identity Provider (IdP)**.
## Prerequisites
* Admin access to your Modelcode organization, **signed in with email and password** — the SSO settings page is not available to users who signed in with a social provider (GitHub, GitLab, Microsoft)
* An identity provider that supports SAML 2.0 (e.g., Okta, OneLogin, PingFederate, ADFS, Azure AD)
* Privileges in your identity provider to create and edit applications and policies
## Step 1: Get Modelcode's Service Provider Details
Before configuring your identity provider, you need two values from Modelcode:
| Field | Description |
| ---------------- | ------------------------------------------------------------------------------------- |
| **ACS URL** | The Assertion Consumer Service URL where your identity provider sends SAML responses. |
| **SP Entity ID** | The unique identifier Modelcode uses as a Service Provider. |
To get these values:
1. Navigate to **Single Sign-On** in the Modelcode sidebar
2. Click **Setup SSO** and select **SAML 2.0**
3. The **ACS URL** and **SP Entity ID** are displayed at the top of the form — copy them for use in your identity provider
If you don't see these values yet, navigate to the SSO settings page and select SAML 2.0 — they are displayed on the form.
## Step 2: Create a SAML Application in Your Identity Provider
In your identity provider, create a new SAML 2.0 application and configure it with:
* **ACS URL** (also called "Reply URL" or "Single Sign-On URL"): Paste the ACS URL from Modelcode
* **Entity ID** (also called "Audience URI" or "Identifier"): Paste the SP Entity ID from Modelcode
* **Name ID Format**: `EmailAddress` (Modelcode matches users by email)
* **Binding**: HTTP-POST (preferred) or HTTP-Redirect
Your identity provider will give you one of:
* **Metadata URL** — A URL that publishes your IdP's SAML metadata XML (recommended)
* **Or** the following individual values:
* **SSO URL** — The IdP's Single Sign-On endpoint
* **Entity ID** — The IdP's entity identifier
* **Signing Certificate** — The X.509 certificate used to sign SAML assertions
## Step 3: Configure SAML in Modelcode
1. In Modelcode, navigate to **Single Sign-On** in the sidebar
2. Click **Setup SSO** (or **Edit** if updating)
3. Select **SAML 2.0** as the protocol
4. Choose your configuration method:
Enter the **Metadata URL** from your identity provider. Modelcode automatically extracts the SSO URL, Entity ID, and Signing Certificate from the metadata XML.
| Field | Required | Description |
| ---------------- | -------- | ------------------------------------------------------------------- |
| **Metadata URL** | Yes | The URL where your IdP publishes its SAML metadata. Must use HTTPS. |
Click **Configure manually** to enter the IdP details individually.
| Field | Required | Description |
| ----------------------- | ----------------- | -------------------------------------------------------------------------------------------------------------------------- |
| **SSO URL** | Yes | The IdP's Single Sign-On service URL. Must use HTTPS. |
| **Entity ID** | Yes | The IdP's entity identifier (also called "Issuer"). |
| **Signing Certificate** | Yes (first setup) | The X.509 certificate from your IdP, in PEM format. On subsequent edits, leave unchanged to keep the existing certificate. |
5. Click **Verify & Save**
Modelcode validates the configuration by checking that the metadata URL returns valid XML (if using metadata) or that the SSO URL is reachable (if using manual configuration).
## Step 4: Invite Users and Share the Portal Link
Before users can sign in via SSO, they must be invited to Modelcode:
1. Go to the [Members](https://morph.modelcode.ai/user-roles?tab=users) page in Modelcode and invite each user who needs SSO access
2. Copy the **Portal Link** from the Single Sign-On settings page and share it with your team:
```
https://morph.modelcode.ai/sso-portal/
```
## Supported SAML Providers
Any provider that supports SAML 2.0 with HTTP-POST or HTTP-Redirect binding works with Modelcode. Common providers include:
* **Okta** — See the [Okta guide](/setup/sso/okta) for step-by-step instructions
* **OneLogin**
* **PingFederate / PingOne**
* **Microsoft ADFS**
* **Azure AD / Microsoft Entra ID** (also supports OIDC)
* **Google Workspace** (also supports OIDC)
## Troubleshooting
### "Verification failed" when saving with a Metadata URL
* Confirm the URL uses HTTPS and is publicly reachable
* Verify the URL returns a valid SAML metadata XML document
* Check that the metadata contains a `SingleSignOnService` element with an HTTP-POST or HTTP-Redirect binding
### "Verification failed" when saving with manual configuration
* Confirm the **SSO URL** uses HTTPS and is reachable
* Verify the **Entity ID** matches what your identity provider reports
* Check that the **Signing Certificate** is a valid X.509 certificate in PEM format
### Users see an error after authenticating with the IdP
* Verify the **ACS URL** in your identity provider exactly matches the value shown in Modelcode
* Confirm the **SP Entity ID** in your identity provider matches the value shown in Modelcode
* Check that the **Name ID Format** is set to `EmailAddress` in your IdP
* Ensure the user's email address in your identity provider matches their Modelcode account email
* Users must be invited to the organization before they can sign in via SSO — SSO does not allow self-registration
* The user's email in the identity provider must be verified — unverified emails are rejected
### SAML assertion signature validation fails
* The signing certificate in Modelcode may be outdated. If your IdP rotated certificates, update the certificate in the Modelcode SSO settings (or re-import via metadata URL)
# Single Sign-On
Source: https://docs.modelcode.ai/setup/sso/single-sign-on
Connect your identity provider to Modelcode for centralized authentication
Single Sign-On (SSO) lets your team sign in to Modelcode using your organization's existing identity provider. Instead of managing separate passwords, users authenticate through a provider you already control — such as Okta, GitLab, Amazon Cognito, or any provider that supports OpenID Connect or SAML 2.0.
**To configure SSO, you must be signed in with email and password.** The SSO settings page is not available to admins who signed in with a social provider (GitHub, GitLab, or Microsoft).
## How It Works
Modelcode supports two industry-standard protocols for SSO:
| Protocol | Best For |
| ------------------------- | -------------------------------------------------------------------------------------------- |
| **OpenID Connect (OIDC)** | Modern identity providers with discovery endpoints (GitLab, Auth0, Cognito, Azure AD) |
| **SAML 2.0** | Enterprise identity providers with XML-based federation (Okta, OneLogin, PingFederate, ADFS) |
Both protocols provide the same end-user experience — your team signs in through your identity provider, and Modelcode handles the rest.
**We recommend SAML 2.0 when your identity provider supports it.** SAML is typically quicker to set up — most providers let you configure it with a single metadata URL, without needing to manage client secrets or authorization server policies.
### What Happens When SSO Is Enabled
1. An admin configures the connection between Modelcode and your identity provider
2. Modelcode generates a **Portal Link** — a unique URL for your organization
3. Team members visit the Portal Link and are redirected to your identity provider to authenticate
4. After signing in, they are redirected back to Modelcode with an active session
## The SSO Portal
Every organization with SSO enabled receives a dedicated **Portal Link**. This is the URL your team uses to sign in via your identity provider.
The portal link follows this format:
```
https://morph.modelcode.ai/sso-portal/
```
You can find your portal link on the **Single Sign-On** settings page after configuring your provider. Share this link with your team — it's the entry point for SSO-based sign-in.
Bookmark your Portal Link or add it to your internal wiki so team members can find it easily.
## SSO and Invitations
Users must be invited to your organization before they can sign in with SSO. SSO does not allow self-registration — an admin must send an invitation first. When SSO is enabled, invited users are automatically routed through your identity provider. The invitation email includes a link that takes the user through the SSO flow instead of the standard password-based sign-up.
If a user tries to sign in via the Portal Link without an existing invitation or account, they will see: **"Your organization uses SSO. Please ask your administrator for an invitation to join."**
## Prerequisites
* A Modelcode account with admin access, **signed in with email and password** — the SSO settings page is not available to users who signed in with a social provider (GitHub, GitLab, Microsoft)
* An identity provider that supports **OpenID Connect** or **SAML 2.0**
* Privileges in your identity provider to create and edit applications and policies
## Setting Up SSO
To configure SSO, navigate to **Single Sign-On** in the Modelcode sidebar. From there you can:
1. Choose your protocol — **OpenID Connect** or **SAML 2.0**
2. Enter your identity provider details
3. Click **Verify & Save** to validate the connection and activate SSO
Modelcode validates the connection before saving. For OIDC, it fetches the discovery document. For SAML, it parses the metadata or validates the SSO endpoint.
All SSO URLs must use HTTPS. HTTP is not accepted for production configurations.
## Provider Guides
Choose the guide that matches your identity provider:
### By Protocol
* [OpenID Connect (OIDC)](/setup/sso/oidc) — Generic OIDC setup for any compliant provider
* [SAML 2.0](/setup/sso/saml) — Generic SAML setup for any compliant provider
### By Identity Provider
* [Okta](/setup/sso/okta) — Configure Okta with SAML 2.0 or OpenID Connect
* [Amazon Cognito](/setup/sso/cognito) — Configure Amazon Cognito as an OIDC identity provider
## Removing SSO
To remove your SSO configuration, go to the **Single Sign-On** settings page and click **Remove SSO**. This disconnects your identity provider. Existing user accounts are not deleted — users can continue to sign in with any other supported authentication method.
Removing SSO revokes active sessions for users who were signed in via SSO. They will need to sign in again using another method.
## Important Behaviors
### Password Reset Is Disabled for SSO Users
Once a user authenticates through SSO, password reset is no longer available for their account. Since authentication is managed by your identity provider, password changes must be handled there — not in Modelcode.
If a user needs to change their credentials, direct them to your identity provider's self-service password reset flow.
## Troubleshooting
### Portal Errors
These are common errors users may see on the SSO Portal page:
| Error | Cause | Resolution |
| ------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| **"Your organization uses SSO. Please ask your administrator for an invitation to join."** | The user has no account or invitation for this organization. | Admin must send an invitation before the user can sign in via SSO. |
| **"Your email is already associated with a different SSO identity."** | The user's email is linked to a different identity provider account. | Contact your administrator to resolve the identity conflict. |
| **"This account belongs to a different organization."** | The user authenticated with an account that belongs to a different organization. | Use the Portal Link for the correct organization. |
| **"Your identity provider has not verified this email address."** | The identity provider did not mark the user's email as verified. | Verify the email address in your identity provider before retrying. |
| **"Single sign-on failed."** | A general authentication failure occurred. | Try again. If the issue persists, check the SSO configuration and contact support. |
| **"Your identity provider returned an error."** | The identity provider itself failed or rejected the login attempt. | Check your identity provider's logs for details. The user may need to retry or the IdP configuration may need attention. |
### "SSO Not Found" on the Portal Page
The SSO configuration may have been removed or the Portal Link URL is incorrect. Check the **Single Sign-On** settings page to confirm SSO is still active and verify the URL.
# Supported Architectures
Source: https://docs.modelcode.ai/setup/supported-architectures
The project types, languages, and application shapes that Morph currently supports
keeps expanding the kinds of modernization projects it can take on. This page describes what is supported **today** so you can pick projects that will produce the best results, and know what to expect before you start.
This list reflects the current state of the platform. We are actively adding support for more languages, frameworks, and application types — check back regularly, and reach out to [support@modelcode.ai](mailto:support@modelcode.ai) if you have a use case you'd like to see covered.
***
## At a Glance
supports **backend, full-stack, and architectural modernization projects**, with capabilities expanding through ModelDaemon.
| Dimension | What's supported today |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Project shape | One or many source repositories → one or many target repositories (1:1 or many-to-many) |
| Transformation type | Language-to-language translation or framework upgrades, architectural transformations |
| Backend | All common backend languages and frameworks (see [Supported Languages](#supported-languages) below) |
| Frontend | All common frontend languages and frameworks (language-to-language translation and framework/runtime migrations) |
| Application shape | RESTful services, CLI tools, and full-stack applications |
| Runtime environment | **Linux** (amd64 or arm64) and **Windows** (amd64) on [Modelcode Hosted](/setup/build-environment/modelcode-hosted) and [self-hosted ModelDaemon](/setup/build-environment/self-hosted-daemon); **macOS** (Apple Silicon or Intel) as a self-hosted daemon host |
| Dev environment | Assisted setup via lifecycle discovery (developer input may be required) |
| Testing | CLI, API, and UI-based validation supported |
***
## Project Shape
supports both **single-repo and multi-repo modernization projects**.
### One-to-One (1:1)
* One source repository → one target repository
* Can be in-place migration or full rewrite
### Multi-Repo (Many-to-Many)
* Multiple source repositories → multiple target repositories
* Supports:
* Monolith → microservices decomposition
* Cross-repo transformations
* Service extraction and restructuring
***
## Transformation Types
supports multiple categories of transformation depending on the scope of your system.
***
### 1. Backend Modernization (Core Capability)
Backend migration projects with the following attributes:
* Many-to-many or one-to-one repository transformations
* Language-to-language translation or framework upgrades
* Target applications may be RESTful APIs, CLI tools, or service-oriented systems
* Supports monolith → microservices transformations
* macOS and POSIX-compatible Linux distributions
* Windows 10/11 and Windows Server 2019+ (amd64 only — Windows on ARM is not supported)
Morph capabilities:
* Detects dependencies and architecture across repositories
* Generates and executes structured migration milestones
* Assists in identifying missing metadata and configuration
* Supports build, run, and test workflows within the target environment
***
### 2. Full-Stack Modernization
Projects that include both backend and frontend components:
* Backend and frontend systems (e.g., PHP + Twig → Java/Spring + React)
* Frontend framework migrations (e.g., Angular → React, Twig → React)
* Multi-repo or mono-repo architectures supported
* Requires lifecycle configuration for frontend build and test processes
Morph capabilities:
* Understands cross-layer dependencies between backend services and UI layers
* Generates frontend transformations aligned with backend changes
* Supports validation through build and test workflows where available
* Assists with configuration of frontend tooling and environments
***
### 3. Architecture & Refactoring Transformations
Projects focused on improving system structure and maintainability:
* Monolith → microservices decomposition
* Service extraction, consolidation, or restructuring
* Codebase refactoring without full language migration
* Dependency standardization and modernization
Morph capabilities:
* Builds architectural understanding across repositories
* Applies transformations incrementally through milestones
* Maintains compatibility with existing system behavior
* Enables iterative modernization without requiring full rewrites
***
## Supported Languages
supports modernization projects whose source and/or target is one of the following languages:
## For each of the above, all common frameworks and micro-frameworks (web, RPC, CLI, background worker, etc.) are in scope.
## Application Shape
The target application can be:
* A **RESTful service** (HTTP API, gRPC gateways, etc.)
* A **command-line (CLI)** tool
* A **full-stack application** (backend + frontend)
validates migrations by executing build, test, and runtime workflows.
* CLI and API-based validation are fully supported
* UI-based validation is supported where build/test workflows are available
***
## Environment & Execution Model
operates directly within your application environment via ModelDaemon.
* With ModelDaemon, execution environments are more portable and less dependent on fixed filesystem or container assumptions
* Lifecycle discovery and guided setup assist in configuring build and runtime environments
* In complex or highly customized systems, developer input may still be required
For best results:
* The application should build and run in the target environment
* Dependencies (services, APIs, packages) should be accessible
* Testable workflows (CLI, API, or UI-based) should be available
***
## What's Not Fully Supported Yet
is built for **backend services, CLIs, and full-stack web apps**. The following kinds of projects are **not supported as modernization migrations today**:
* **Native mobile applications** — iOS, Android, and other mobile-first stacks (device SDKs, mobile UI frameworks, app-store packaging workflows)
* **Desktop GUI applications** — thick-client or native desktop apps whose primary artifact is a desktop installable (as opposed to a service or web app you run locally)
* **Plugins and extensions** — IDE plugins, browser extensions, editor extensions, and other code that runs inside a host application rather than as a standalone service or site
If your project mixes supported and unsupported surfaces (for example, a web API plus a mobile client), focus the migration on the supported components or contact [support@modelcode.ai](mailto:support@modelcode.ai) before committing. For any complex requirements, validate setup during project initialization.
***
## Evaluation & Performance
Morph performance is continuously evaluated across single-repo and multi-repo modernization scenarios.
* Supports both single-repo and multi-repo transformations
* Designed to achieve high test pass rates and successful milestone completion
* Outcomes vary depending on system complexity, dependency availability, and test coverage
***
## Checking Whether Your Project Is Supported
does not pre-screen your modernization goal, so use the guidance on this page to judge fit before you begin. If your project sits close to the boundary — or mixes supported and unsupported surfaces — contact [support@modelcode.ai](mailto:support@modelcode.ai) before committing.
Once the project is created, the Project Spec is where scope becomes concrete. Changes are cheapest here — later course corrections mean editing milestones or adding ad hoc work.
See [Reviewing the Project Spec](/setup/reviewing-project-spec) for the walkthrough.
***
## Still Not Sure?
If you're unsure whether your project qualifies, or you have a modernization in mind that doesn't quite fit, reach out to [support@modelcode.ai](mailto:support@modelcode.ai).
# Validation Level
Source: https://docs.modelcode.ai/setup/validation-level
Choose how thoroughly Morph validates each milestone — trading speed against stronger guarantees that the modernized app behaves like intended
Every migration faces the same tradeoff: move fast, or prove correctness. The **validation level** is a single project-wide setting that lets you decide where you sit on that spectrum. It controls how much work invests in verifying each milestone — the build-and-run lifecycle, [functional testing](/migration/functional-testing), [acceptance criteria](/setup/build-environment/acceptance-criteria), and source environment setup.
A lower level moves faster and requires less setup. A higher level gives you stronger, evidence-backed guarantees that the modernized app behaves as described in your [project spec](/setup/reviewing-project-spec) — at the cost of more upfront configuration and longer milestone runs.
Validation level applies to the **whole project** and affects **every milestone**. You set it once during onboarding and can change it later from the project overview.
***
## The Three Levels at a Glance
| Dimension | Low — Fast | Medium — Balanced | High — Thorough |
| ----------------------------------------------------------------------- | ------------- | --------------------------- | ------------------------------------- |
| **Target build + unit tests** | ✅ Best-effort | ✅ | ✅ |
| **Full target lifecycle** (run, health checks) | ❌ | ✅ | ✅ |
| **[Functional testing](/migration/functional-testing)** | ❌ Off | ⚠️ Target-only | ✅ Full (baseline captured + verified) |
| **[Acceptance criteria](/setup/build-environment/acceptance-criteria)** | ❌ None | ⚠️ Target-only (you author) | ✅ Full (baseline captured + verified) |
| **Source environment setup** | ❌ | ❌ | ✅ Upfront |
| **Speed** | 🚀 Fastest | ⚖️ Balanced | 🐢 Slowest |
| **Confidence** | Low | Medium | High |
Each level is a strict superset of the one below it — Medium does everything Low does and more, and High does everything Medium does and more.
***
## Low — Fast
The fastest path. Morph builds the target and runs unit tests each milestone on a best-effort basis, then moves on.
**What you gain**
* The shortest milestone runtimes and the quickest route to a complete roadmap.
* No environment setup required before you start.
**What you give up**
* No app-run or health-check lifecycle — the migrated app is never actually started and exercised.
* No [functional testing](/migration/functional-testing), so deviations from the behavior described in your spec go undetected.
* No [acceptance criteria](/setup/build-environment/acceptance-criteria) — there is no formal definition of "done" beyond compilation and unit tests.
**Best for** prototypes, throwaway experiments, internal tooling, or migrations where you intend to validate behavior yourself downstream.
***
## Medium — Balanced
A middle ground that proves the target actually runs, without requiring Morph to stand up your source application's environment.
**What you gain**
* Everything in Low, plus the **full target lifecycle**: Morph builds, runs, and health-checks the migrated app each milestone.
* **Target-only [functional testing](/migration/functional-testing)** — tests are generated and executed against the migrated app to confirm it behaves sensibly.
* **Target-only [acceptance criteria](/setup/build-environment/acceptance-criteria)** — you author absolute-threshold quality gates (for example, "line coverage ≥ 80%") that Morph enforces on the target.
**What you give up**
* No **captured baseline**. Tests and acceptance criteria confirm the modernized app works and meets the thresholds you author, but Morph never observes the source app's real behavior — so you define what "correct" means up front, rather than having it captured for you.
* No source environment setup.
**Best for** greenfield-style rewrites, projects where the source app can't be run, or cases where confirming the app runs and meets your authored thresholds is enough.
***
## High — Thorough
The strongest guarantee. Morph sets up your **source** application upfront, captures its real behavior as a baseline, and verifies the modernized app behaves as the spec describes.
**What you gain**
* Everything in Medium, plus **upfront source environment setup** so the source app can be run and observed.
* **Full [functional testing](/migration/functional-testing)** — Morph captures a behavioral baseline from your source app, runs the modernized app, and verifies it behaves as the spec describes, surfacing any regression side by side.
* **Full [acceptance criteria](/setup/build-environment/acceptance-criteria)** — Morph discovers metrics on the source app, captures their baseline values, and translates them into target-side gates, on top of any criteria you author.
**What you give up**
* The most setup effort and the longest milestone runtimes.
* You must provide enough detail for Morph to stand up the source environment (dependencies, run commands, credentials, and so on).
High validation is the recommended default for production migrations where behaving exactly as the spec describes is a hard requirement.
**Best for** production migrations, regulated or business-critical systems, and any project where "the modernized system must behave exactly as specified" is non-negotiable.
***
## Choosing the Right Level
Ask yourself two questions:
1. **Does the modernized app need to behave *exactly* as described in the spec?** If yes, choose **High** — it's the only level that captures a behavioral baseline from your source app and verifies against it.
2. **Can your source application be run in an environment Morph can access?** If no, **High** isn't viable; choose **Medium** to still validate that the target runs and meets your authored thresholds.
If neither equivalence nor runtime validation matters — you only need code that compiles and passes unit tests — choose **Low** for the fastest path.
| Your priority | Recommended level |
| ------------------------------------------------------------- | ----------------- |
| Behaving exactly as described in the spec | **High** |
| Confidence the target runs correctly, no source app available | **Medium** |
| Maximum speed, minimal setup | **Low** |
***
## Setting the Validation Level
You configure the validation level from the **Validation Level** panel in the project overview. During onboarding it appears as a guided next step.
From the project overview, open the **Validation Level** configuration panel.
Select **Low**, **Medium**, or **High**. The panel summarizes what each option includes so you can compare the tradeoffs in context.
Saving applies the level to the entire project and every milestone in it.
If you choose **High**, Morph opens a short setup chat to capture your source environment details and acceptance criteria. This is what lets Morph baseline the source app and verify the modernized app against the spec.
If you don't pick a level, projects default to **High** — the safest choice when behavioral equivalence matters. Your organization may configure a different default.
***
## Per-Milestone Validation Indicator
Each milestone card on the Roadmap shows a small **validation level indicator** below its title — a bar-chart icon with a label (Low, Mid, or High). This indicates the **effective validation level** that is currently applied and with which the milestone will run.
The effective level is determined by:
* The milestone's own recorded validation level (stamped at execution time), **or**
* The project-level validation level (if the milestone hasn't run yet).
This lets you see at a glance which milestones were validated at which depth — especially useful after changing the level mid-project.
***
## Changing the Level Between Milestones
You can upgrade or downgrade the validation level between milestones. Open the Validation Level panel, select a new level, and click **Save**. A confirmation dialog explains what will happen before any change is applied.
The validation level cannot be changed while a milestone is currently in progress. Wait for the running milestone to complete before adjusting.
### Upgrading
When you upgrade to a higher level:
| Scenario | What happens |
| ------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **No milestones merged yet** | The new level applies to the next milestone. No extra action needed. |
| **Milestones already merged (upgrade to Medium)** | automatically launches an **ad-hoc validation run** on the last merged milestone to cover the functional tests and acceptance criteria that the lower level skipped. |
| **Upgrade to High** | A short setup chat opens first to capture origin environment details and acceptance criteria. After setup completes, an ad-hoc validation run is launched on the last merged milestone. |
The ad-hoc validation run appears on the Roadmap as a numbered validation milestone (e.g., "Validation 1.1") and must complete before the next standard milestone can start.
### Downgrading
Lowering the validation level reduces checks for **future** milestones only. Completed milestones are not affected — their validation results stay as-is.
***
## Running a Single Milestone at Low
Sometimes one milestone is expensive to validate at the project's level — a slow or unreliable app runtime where builds or health checks take ten minutes or more. For those cases you can run **that milestone only** at Low, without changing the project setting.
In the [Project Knowledge](/customization/project-knowledge) drawer, open the caret next to **Approve & Start** and choose **Start With Low Validation**. The milestone is implemented *and* reviewed at Low — build and unit tests only, no lifecycle run, functional testing, or acceptance criteria — regardless of the project's level. Its milestone card records **Low**, so the [validation indicator](#per-milestone-validation-indicator) reflects the level it actually ran at.
This is a discouraged, advanced option. Reach for it only when the app runtime is the bottleneck, not to skip checks by preference. After the milestone's PR merges, run an [ad-hoc validation](#on-demand-validation-rerun) to cover the project's real level. If your environment is healthy, use **Approve & Start**.
***
## On-Demand Validation Rerun
After a milestone is merged, you may see a **Rerun Validation Suite** button appear between milestones on the Roadmap. This lets you retroactively validate a merged milestone at the project's current validation level.
### When It Appears
The rerun trigger is shown when **all** of these conditions are true:
* The previous milestone is merged.
* The project's current validation level is higher than the level recorded on that milestone.
* No ad-hoc validation is already running or pending for that milestone.
* The next standard milestone hasn't started yet.
### How It Works
1. Click **Rerun Validation Suite** on the divider between milestones.
2. creates an ad-hoc validation milestone (e.g., "Validation 2.1") that reruns the full validation suite at the project's current level.
3. The ad-hoc milestone appears in the Roadmap and shows progress like any milestone — with review tasks, test results, and status badges.
4. The next standard milestone is blocked until the ad-hoc validation completes.
Starting a validation run requires permission to run executions on the project. If you don't see the button, ask your workspace admin.
### If a Validation Run Fails
If the ad-hoc validation encounters an error, the milestone card shows a failure alert with a **Retry** button. Click it to re-run the validation suite without creating a new milestone.
***
## Related Docs
How Morph generates, runs, and compares functional tests
Quantitative quality gates enforced on every milestone
Configure how your project builds and runs
The three-step process that validation level shapes
# Billing & Credits
Source: https://docs.modelcode.ai/support/billing-and-credits
How usage-based billing works on the Morph Platform
## How Billing Works
uses a **credit-based billing model**. Credits are the unit of usage that measures the work performed on your codebase. Your plan includes monthly credits, and any usage beyond that is billed at a per-credit rate.
Three things are worth knowing up front, because they shape how the whole model feels in practice:
* **Planning and design are free.** Analyzing your codebase, generating your Project Spec, and planning your roadmap never cost credits. You spend credits only when writes and ships code.
* **Overage is approved, not assumed.** A milestone that would go beyond your monthly allotment shows the exact amount and does not run until you approve it. Nothing is spent silently.
* **Your card is validated, not charged.** Payment details are collected when you activate your account so usage-based billing can be switched on. You are not charged at that point.
The cost-approval step applies to plans on the credit-based billing model described here. Some organizations — for example self-managed deployments or custom billing arrangements — don't see it, and milestones start without a cost confirmation. Check with your workspace admin if you're unsure how your organization is billed.
## What Consumes Credits
Credits are consumed when a milestone produces a pull request — not when it starts. If a milestone fails or you cancel it, the credits reserved for it are released back to you.
Before each milestone runs, estimates its credit cost based on the scope of work involved. The actual cost depends on the complexity of the changes.
## Approving a Milestone's Cost
Starting a milestone opens a **Start this milestone?** dialog showing what the run will cost, in both dollars and credits, before anything happens.
Each milestone card also carries its credit estimate, so the cost is visible before you open anything:
What you see depends on where the milestone lands against your monthly allotment:
* **Inside your included credits** — the dialog tells you how many credits you will have left afterward, and the button reads **Approve & start**. Nothing is charged.
* **Beyond your included credits** — the dialog shows how many credits go past your allotment and at what rate, and the button reads **Approve** with the amount. You are billed when the pull request is created.
Where the dialog applies, it is not something you can turn off — spend on your codebase should be a decision you make, not something you discover on an invoice.
The dialog prices the run against credits you have already used **and** credits committed to milestones currently in flight. Approving two milestones back to back gives you an accurate figure for the second one, not a stale one.
## Your Included Credits
Your plan includes **40,000 credits per month**. This resets at the start of each billing cycle. Unused credits do not carry over.
If your usage exceeds the included credits, additional credits are billed at **\$0.01 per credit**. Approved overage is billed to your payment method on file when the milestone's pull request is created.
## Promo Codes
If you have a promo code, enter it under **Have a promo code?** on the payment page and click **Apply**. Codes can add bonus credits to your monthly allotment, and may apply for a set number of months. Applied codes appear as a badge showing what they granted.
## Checking Your Balance
Your current credit usage is visible in the application dashboard. The credit gauge shows:
* **Available** — credits you can still spend
* **Used this period** — credits already consumed
* **In progress** — credits committed to milestones currently running
* **Included / month** and **Over allotment**
* Your next billing cycle reset date
If you are not an administrator, the gauge points you to your admin to manage billing.
## Seats
Your plan includes a set number of seats, shown on the **Members** screen as `3 of 5 seats used`.
When every seat is in use, the invite and create-user flows will not open until a seat is freed. On -hosted plans you can raise your seat count from the **Billing** page. On self-managed deployments, remove a member or revoke a pending invitation to free one up.
## Plan Details
| | Pro |
| --------------- | ------------- |
| Base price | \$0/seat/mo |
| Monthly credits | 40,000 |
| Overage rate | \$0.01/credit |
| Projects | Unlimited |
| Lines of code | Unlimited |
Payment details are collected when you activate your account, but your card is only validated — you are not charged until you approve a milestone that goes beyond your included credits.
## Frequently Asked Questions
### When do my included credits reset?
Credits reset at the start of each monthly billing cycle. The exact date is shown in your credit gauge and on the Billing page.
### Can I see cost estimates before running a milestone?
Yes. Each milestone shows an estimated credit cost on the milestone card in your project view. When you start a milestone, confirms the cost with you first — showing the credits and, if the work would exceed your monthly allotment, the dollar amount — before any work begins.
### What happens if I exceed my monthly credits?
Any milestone that would push you past your included credits shows the overage amount and starts only after you approve it. Approved overage is billed at the per-credit rate when the milestone's pull request is created, and the charge appears on your payment method on file.
### What if a milestone fails after I approved it?
The credits reserved for it are released back to you. You are billed when a milestone produces a pull request, so work that never gets there does not cost you credits.
### Does reviewing or planning cost credits?
No. Codebase analysis, Project Spec generation, and roadmap planning are free. Credits are consumed by milestone execution — including the validation and review that run as part of it.
# FAQ
Source: https://docs.modelcode.ai/support/faq
Frequently asked questions
## Getting Started
### What can I use for?
automates code modernization, including:
* **Language upgrades** — Python 2 to 3, Java 8 to 21
* **Language translations** — Ada to C++, COBOL to Java
* **Framework migrations** — AngularJS to React, Express to FastAPI
* **Architecture modernization** — Refactoring to modern patterns
### Does modify my original code?
No. Your original repositories are never modified directly. works on a dedicated feature branch (prefixed with `morph-`) and delivers changes as Pull Requests. You always control what gets merged.
### What languages does support?
supports a wide range of languages including:
* Python, Java, JavaScript, TypeScript
* C, C++, C#, Go, Rust
* Ada, COBOL, Kotlin, PHP
* And more
Contact support for specific language or framework capabilities.
## The Migration Process
### How long does a migration take?
It depends on:
* Repository size
* Complexity of the transformation
* How quickly you review and merge PRs
Each milestone typically takes minutes to hours to execute. The overall timeline depends on how many milestones and your review cadence.
### Can I stop a migration partway through?
Yes. Milestones are independent once merged. You can:
* Stop after any milestone
* Continue later
* Choose not to proceed with remaining milestones
Each merged milestone produces working code.
### What if I don't like the generated code?
Every milestone produces a Pull Request that you review before merging:
* **Make manual edits** — Change anything in the PR
* **Request regeneration** — Close the PR and retry with edited milestone
* **Create rules** — Prevent the issue in future milestones
You're never forced to accept code you don't want.
### Can milestones run in parallel?
Yes. Milestones that are independent — meaning they don't share file dependencies — can be approved and executed at the same time. Each runs on its own branch and produces its own PR. When one merges, checks whether sibling branches need a rebase and handles it automatically. Milestones that *do* depend on earlier ones remain locked until their prerequisites merge.
## Security & Privacy
### Is my code secure?
Yes:
* Your code is accessed only to perform the migration
* We use secure, encrypted connections
* Code is not shared with third parties
* Contact us for enterprise security requirements
### Can I use with private repositories?
Yes. When connecting your Git provider (GitHub, GitLab, or Azure DevOps), grant access to specific private repositories. only accesses repositories you explicitly authorize.
### Where does the migrated code go?
commits generated code to the project's feature branch and delivers changes as Pull Requests. Each repository in the project has a defined role (Modified, New, Reference Only, One-to-One Migration), and PRs are created accordingly. You must review and merge PRs yourself.
## Project Spec & Rules
### What's the difference between the Project Spec and Rules?
| Project Spec | Rules |
| --------------------------------- | ------------------------------------ |
| Define the overall migration goal | Define coding standards and patterns |
| Set once at project start | Added anytime during migration |
| Describe what to migrate | Describe how to write code |
| Approved, then locked | Can be edited or deleted |
Both work together. The Project Spec sets direction; rules fine-tune execution.
### Can I change the Project Spec after approval?
No. An approved Project Spec is locked because it's the foundation for all generated milestones. If you need different goals or scope at that level:
* Create rules to influence how milestones execute
* Edit individual milestones before generating their tasks
* For major changes, consider starting a new project
### When should I create a Rule?
Create rules when you:
* Know exactly what you want (coding conventions, library choices)
* See the same issue across multiple milestones
* Have company standards that must be followed
* Want to prevent specific patterns in generated code
## Milestones
### Can I edit a milestone after tasks are generated?
No. Once tasks are generated, the milestone is locked for that execution. To make changes:
1. Let the execution complete
2. Review the PR
3. Make manual edits to the PR, or
4. Close the PR and edit the milestone for a fresh execution
### What if a milestone fails?
1. Check the error message
2. Click **Retry**
3. If it keeps failing, review the milestone description for issues
4. Contact support with the error details if needed
### Can I skip a milestone?
Not directly. Milestones that have dependents must be completed before those dependents can start. You can, however, edit a milestone to effectively no-op it if needed.
## Technical
### What happens to my tests?
can:
* Migrate existing tests to the new framework
* Generate new tests for migrated code
Specify your testing preferences in your modernization goal or via Rules.
### What about dependencies?
handles dependency updates:
* Identifies equivalent packages in the target ecosystem
* Updates import statements
* Generates new dependency configuration (package.json, requirements.txt, etc.)
### Does handle database migrations?
For schema changes, can generate migration files (e.g., Alembic for Python). Specify database migration requirements in your Project Spec or rules.
### What about environment variables and config?
Configuration files are migrated based on your Project Spec. Specify any special handling needed in your modernization goal or rules.
## Billing & Accounts
### How does billing work?
Modelcode uses credit-based billing. Your plan includes a monthly credit allotment. Credits are consumed when milestones execute. See [Billing & Credits](/support/billing-and-credits) for current plan details and pricing.
### Can multiple team members use one project?
Yes. Plans support multiple seats. See [Billing & Credits](/support/billing-and-credits) for seat pricing details.
## Getting Help
### How do I contact support?
Email **[support@modelcode.ai](mailto:support@modelcode.ai)** with:
* Your project name
* Description of the issue
* Any error messages
* Screenshots if helpful
### Where can I request features?
Email **[feedback@modelcode.ai](mailto:feedback@modelcode.ai)** with your suggestions. We actively incorporate user feedback into our roadmap.
# Troubleshooting
Source: https://docs.modelcode.ai/support/troubleshooting
Solutions to common issues
This guide covers common issues and how to resolve them.
## Generation Failures
### Codebase Analysis Failed
**What happened:** couldn't analyze your repositories.
**Try these:**
1. **Check repository access** — Ensure has permission to read your repositories
2. **Verify the repositories are accessible** — Try accessing them directly in your Git provider
3. **Click Try Again** — Transient errors often resolve on retry
4. **Check repository size** — Very large repositories may need more time
If failures persist, contact support with your project name.
### Project Spec generation failed
**What happened:** couldn't generate the Project Spec from your goal.
**Try these:**
1. **Make your goal more specific** — Vague goals are harder to process
2. **Check your modernization goal** — Does it describe a clear transformation?
3. **Click Try Again** — Retry often resolves transient issues
### Roadmap Generation Failed
**What happened:** couldn't plan the milestone sequence or generate the roadmap.
**Try these:**
1. **Review your Project Spec** — Are there conflicting requirements?
2. **Check for complex requirements** — Unusual combinations may cause issues
3. **Click Try Again** — Transient errors may resolve
## Build Environment Issues
### Validation Failed
**What happened:** The end-to-end validation of your build environment didn't pass.
**Try these:**
1. **Check lifecycle commands** — Verify that install, build, run, and test commands work when run manually
2. **Check environment variables** — Missing or incorrect variables are a common cause
3. **Review the validation logs** — They show which step failed and the error output
4. **For Self-hosted Daemon** — Ensure the daemon is online and has access to required services (private registries, databases, APIs)
### Health Check Timed Out
**What happened:** The application started but the health check never succeeded.
**Try these:**
1. **Confirm the health check URL and port** — They must match your application's configuration
2. **Check that the application binds to the correct interface** — Use `0.0.0.0` or `localhost`
3. **Increase the timeout** — If your application has a long startup sequence
### Daemon Shows as Offline
**What happened:** has not heard from one of the machines in your project's pool.
**Start in the app:** open the **Daemon pool** section in your project's Roadmap sidebar. It shows how many machines are online and which one is not, which tells you straight away whether this is one machine or the whole pool. If other machines are online, your work is not blocked — it will route to them.
**Then, on the affected machine**, ask whoever administers it to check that the daemon is running, that outbound HTTPS is not blocked by a recent VPN or firewall change, and that its logs show no authentication errors.
The most common cause is a host that rebooted without the daemon being installed as a service, so nothing brought it back up.
See [Daemon Administration](/setup/build-environment/daemon-administration#when-a-daemon-shows-as-offline) for the full diagnostic steps.
## Milestone Issues
### Task Execution Failed
**What happened:** One or more tasks failed during milestone execution.
**Try these:**
1. **Expand the milestone** — See which task failed and the error message
2. **Click Retry** — Many failures are transient
3. **Review the milestone description** — Unclear instructions can cause failures
4. **Check lifecycle commands** — Incorrect install/build/test commands configured in the build environment can fail execution
For persistent failures, contact support with the error message.
### PR Generation Failed
**What happened:** Tasks completed but the Pull Request couldn't be created.
**Try these:**
1. **Click Retry PR** on the milestone card — Often resolves the issue
2. **Check permissions** — needs permission to create branches and PRs in your Git provider
3. **Check branch protection rules** — Some rules may block automated PRs
4. **Verify repository access** — Ensure permissions haven't changed
### PR Checks Failed
**What happened:** The Pull Request was created but CI/CD checks failed.
**This is normal.** The generated code may need adjustments for your specific CI pipeline.
**Try these:**
1. **Review the failing checks** — Understand what failed
2. **Common causes:**
* Linting violations (style doesn't match your config)
* Test failures (some tests may need updates)
* Build errors (configuration differences)
3. **Make manual fixes** — Push additional commits to the PR
4. **Merge when checks pass**
For recurring issues, consider creating [Rules](/customization/rules) to prevent them.
### Milestone Stuck in "In Progress"
**What happened:** The milestone shows as running but nothing is happening.
**Try these:**
1. **Refresh the page** — Status updates may not have rendered
2. **Wait a few minutes** — Some operations take time
3. **Check for errors** — Expand the milestone to see if a task failed
4. **Contact support** — If truly stuck for more than 30 minutes
### Can't Start Next Milestone
**What happened:** The next milestone won't unlock.
**Why this happens:** Milestones respect a dependency graph. A milestone stays locked until all milestones it depends on are merged.
**Check:**
1. **Are all prerequisite milestones merged?** — Look at which milestones yours depends on
2. **Did the prerequisite's PR merge successfully?** — Check in your Git provider
3. **Refresh the page** — polls for merge status periodically
### Milestone Shows "Rebase Required"
**What happened:** A sibling milestone was merged and this milestone's branch now needs to incorporate those changes.
**Why this happens:** When multiple milestones run in parallel and one merges into the feature branch, remaining in-progress branches may diverge.
**Resolution:**
1. Click the **Rebase** action on the milestone card
2. The agent incorporates the upstream changes automatically
3. Once complete, review and merge the updated PR as normal
### Pool Busy — All Workers Busy
**What happened:** You tried to start a milestone, ad-hoc execution, or similar work and saw *"All workers in this project's pool are busy — try again when one frees up."*
**Why this happens:** Every daemon in the project's pool is already running an execution. Non-chat work is blocked until a worker becomes available.
**Resolution:**
1. **Wait** — a running execution will finish and free a worker
2. **Check pool activity** — look at the project sidebar or Build Environment page to see what is running on each daemon
3. **Add capacity** — register additional daemons into the pool to handle more concurrent work
**Knowledge chat** and **Code Review chat** are **exempt** from the pool capacity gate. You can always open a chat session even when all workers are busy with executions.
### Another User Is Using Knowledge Chat
**What happened:** You tried to open a Knowledge chat or Code Review chat session but another user currently has an active session.
**Why this happens:** Chat sessions are locked to one active user at a time to prevent conflicting instructions to the agent.
**Resolution:**
1. **Wait** — the session unlocks when the other user finishes or their session times out
2. **Coordinate** — reach out to the team member shown in the lock message
### Waiting for Exclusive Access / Move to a Free Worker
**What happened:** Your chat session is parked because another job on the same daemon needs exclusive access to the application (for example, running lifecycle commands).
**Why this happens:** Some operations require exclusive control of the application process on the worker. If the daemon is already running such an operation, the chat waits until it finishes.
**Resolution:**
1. **Wait** — the operation will finish and your chat resumes automatically
2. **Move to a free worker** — if the pool has another available daemon, offers a **Move to a free worker** option so your chat can continue on a different daemon without waiting
### Project Not Connected to a Pool
**What happened:** You tried to run work on a self-hosted project but there is no daemon pool connected.
**Resolution:**
1. Go to **Build Environment** in the project settings
2. **Join an existing pool** or create a new one and register a daemon into it
3. Once a pool is connected with at least one online daemon, you can start work
### No Live Daemons in Pool
**What happened:** The project is connected to a pool, but all daemons in the pool are offline.
**Resolution:**
1. Check that at least one daemon host is running `mcode` — run `mcode logs` on the host to see recent errors
2. Verify network connectivity from the host to over HTTPS
3. See [Daemon Administration — When a daemon shows as offline](/setup/build-environment/daemon-administration#when-a-daemon-shows-as-offline) for detailed steps
### Daemon Install Refused on Windows (ARM or 32-bit)
**What happened:** `install.ps1` stopped before installing anything. The ModelDaemon ships for Windows on amd64 only, and the installer checks the host's architecture first:
* *"Error: Windows on ARM is not supported. Use an x64 (amd64) Windows machine."*
* *"Error: mcode has no 32-bit build. … A 64-bit version of Windows is required."*
**Resolution:**
1. Install the daemon on a 64-bit Windows amd64 host instead. Nothing was written on the refusing host, so there is nothing to clean up.
2. If your application has to build on Windows on ARM, contact [support@modelcode.ai](mailto:support@modelcode.ai).
### Daemon Registration Refused
**What happened:** The daemon installed, but registering it into the pool failed. A pool serves one platform, so a daemon is turned away at registration rather than joining and sitting idle. The message says which case you hit:
* *"Daemon OS '…' does not match daemon pool '…'"* — the pool serves the other platform.
* *"Daemon arch '…' does not match target pool arch '…'"* — the pool has an architecture pin and this host reports a different one.
* *"…has live daemons on more than one OS (…). Remove the daemons that do not belong from the pool before adding a new one."* — the pool's membership is inconsistent and has to be settled first.
**Resolution:**
1. Check the pool's **OS** and **Architecture** on the pool details page, and compare them with the host you are installing on.
2. Install the daemon on a host matching the pool, and register it again. This is usually the quickest route.
3. For the third message, open the pool details page and **Move** or **Remove** the daemons whose platform doesn't belong — both need the daemon to be idle — then register the new one.
4. If the host is the one you need and the pool is the wrong fit, create a new pool on that platform and register the daemon into it. A project already connected to the old pool stays there.
### Execution Fails at Sandbox Creation on a Platform Mismatch
**What happened:** An execution failed while its sandbox was being created, because the daemon it was routed to runs a different operating system than the project. The project's platform decides the shell its commands are written in, so the run stops rather than executing them on the wrong one.
The project stays on the pool it was set up with, so the fix is to correct the pool's membership.
**Resolution:**
1. Open the pool details page — **Manage** in the ModelDaemon pool section of the project sidebar — and compare each daemon's operating system with the project's platform.
2. **Move** or **Remove** the daemon that doesn't match, from the pool details page. Both actions need the daemon to be idle, so wait for its current job to finish.
3. Register a daemon running the project's platform into the same pool, so there is somewhere for the work to go.
4. **Retry** the milestone from the roadmap.
If every daemon in the pool runs a different platform than the project, the pool isn't the right home for it — contact [support@modelcode.ai](mailto:support@modelcode.ai) before deleting anything, since both the project's platform and its pool are [set at Build Environment setup](/setup/build-environment/switching-environment).
## Pull Request Issues
### PR Not Detected as Merged
**What happened:** You merged the PR but still shows "Pending Review."
**Try these:**
1. **Refresh page** — Status updates poll periodically
2. **Wait 1-2 minutes** — There's a short delay between merge and detection
3. **Verify in your Git provider** — Confirm the PR is actually merged (not just approved)
4. **Contact support** — If not resolved after several minutes
### Merge Conflicts
**What happened:** The PR has conflicts with the target branch.
**Why this happens:**
* Manual changes were made to the repository between milestones
* Another branch was merged that conflicts
**Resolution:**
1. Resolve conflicts as you normally would in your Git provider
2. Push the resolution
3. Merge the PR
### Can't Open PR
**What happened:** Clicking "Review Pull Request" doesn't open anything.
**Try these:**
1. **Check your popup blocker** — The PR opens in a new tab
2. **Check the milestone status** — Is a PR actually ready?
3. **Refresh and try again**
## Access Issues
### Can't See My Repositories
**What happened:** Your repositories don't appear in the selection list.
**Try these:**
1. **Check your Git provider connection** — You may need to reconnect
2. **Check repository permissions** — Did you grant access to the specific repo?
3. **For organization repos** — You may need admin approval for the app installation
### Can't Create Project
**What happened:** Repository selection or project creation fails.
**Try these:**
1. **Check permissions** — Ensure you have access to the repositories
2. **Try a different repository** — To isolate the issue
3. **Verify app installation** — Ensure the repositories are included in your Git provider's app configuration
## Getting Help
### Contact Support
For issues not covered here:
1. Email **[support@modelcode.ai](mailto:support@modelcode.ai)**
2. Include:
* Your project name
* What you were trying to do
* The error message (if any)
* Screenshots (if helpful)
### Response Times
* **Business hours:** 2-4 hours
* **After hours:** Next business day
# Videos
Source: https://docs.modelcode.ai/support/videos
Short walkthroughs to help you get started with Morph
These videos walk through the main parts of starting and running a modernization project in . Use them as a quick visual guide before you create your first project, approve a spec, or review milestone output.
## Product Walkthrough
See the sample MediaHub application used throughout the walkthrough, including the user experience and application behavior that will preserve during modernization.
Watch on [YouTube](https://youtu.be/cb6SLK0As2o).
## Reviewing Project Knowledge
Learn how to review the Project Spec in Project Knowledge, confirm repository roles, inspect modernization details, and approve the plan before migration work begins.
Watch on [YouTube](https://youtu.be/nJ8FJREogXc).
## Configuring the Environment
Follow the environment setup flow, including lifecycle scripts, environment variables, validation, acceptance criteria, and roadmap generation after onboarding is complete.
Watch on [YouTube](https://youtu.be/L5M2Wri-C2M).
## Reviewing Milestone Output
See how to review milestone results, use review chat to resolve issues, inspect automated review findings, and move from completed work to pull request review.
Watch on [YouTube](https://youtu.be/mP1SyyrGw2g).
# What's New
Source: https://docs.modelcode.ai/support/whats-new
Recent product updates and documentation changes
## September 2026
This month puts you more firmly in control of each milestone — you approve what it costs before it runs, you can keep refining a project spec after you've approved it, and code review gains tagging, effort estimates, and on-demand frontend tests.
### Approve a milestone's cost before it runs
Starting a milestone now opens a short confirmation that shows the estimated **credits** and, when the work would go beyond your monthly allotment, the exact dollar amount. Milestones that fit within your included credits start for free; anything that would incur overage runs only after you approve the charge — nothing bills silently. Credits are deducted when the milestone's pull request is created.
This applies to plans on the credit-based billing model; some organizations, such as self-managed deployments, don't see the confirmation step. See [Billing & Credits](/support/billing-and-credits) for the full model.
### Edit approved project specs
Approving a Project Spec no longer locks it. You can keep refining an approved spec with **Knowledge chat** — adjust its prose or repository topology — the same way you did before approval. If milestone planning has already run, your edits apply to future milestones only; the source repositories chosen at project creation stay fixed.
See [Reviewing the Project Spec](/setup/reviewing-project-spec).
### Code review: tags, effort estimates, and frontend tests
The **Code Review** drawer gained three things:
* **Issue tags.** Create and assign tags to review issues from the issue card, then filter and group the list by them.
* **Effort estimates.** Issues the review agent has sized show a T-shirt-size badge (XS–XL), so you can triage by how much work each one is.
* **Run the frontend tests from chat.** On projects with a frontend, ask the chat to run or re-run the milestone's Playwright suite — for example after it fixes a UI bug. Results and screenshots refresh in the drawer's **Validation** tab when the run finishes.
See [Code Review Chat](/migration/code-review-chat).
### Run a single milestone at Low validation
When one milestone is expensive to validate — a slow or unreliable app runtime — you can run **that milestone only** at the Low level without changing the project setting. Open the caret beside **Approve & Start** in Project Knowledge and choose **Start With Low Validation**. Run an ad-hoc validation after the PR merges to cover the project's real level.
See [Running a Single Milestone at Low](/setup/validation-level#running-a-single-milestone-at-low).
## August 2026
This month makes build capacity a team resource rather than a per-machine one, and deepens what gets checked after every milestone.
### Review and validation, in one place
Code Review is no longer only about issues. The milestone's test results now live alongside them, under a **Validation** tab split into **API/CLI**, **UI Tests**, **QA Agent**, and **Lifecycle**.
Every result has a **Discuss** button that drops it straight into the review chat. Instead of describing a failure to the agent, you hand it the failure.
Failures that opened a review issue now link both ways, so you can get from a red test to the issue tracking it, and back.
### A QA agent that actually explores your application
Frontend validation used to be one agent writing and running browser tests. It is now two, with different jobs.
A **QA agent** explores your migrated application the way a person would, capturing what it finds side by side against the original. A separate **test agent** then writes and runs the automated suite from that report.
The practical difference is coverage you did not have to specify. The QA agent finds the screens and flows that matter by looking, rather than only testing what someone thought to describe — and its paired before-and-after evidence is often the most convincing artifact in a migration review.
### Knowledge that finds itself
Once your Project Spec is approved, Morph reads it and searches your organization's knowledge for anything worth reusing on this project — based on what the migration intends to do, not only on which repositories happen to match.
The result arrives as a selection during onboarding, with the best matches marked **Recommended**. You choose what to bring in.
This is where the second migration starts costing less than the first. Lifecycle knowledge, conventions, and hard-won corrections from earlier projects show up at the beginning instead of being rediscovered.
Relatedly: knowledge import is no longer restricted to projects that share repositories with yours. The whole organizational pool is available, with relevance driving what gets recommended rather than what gets shown. Hover a **Recommended** tag to see why an item was suggested.
### Every milestone re-checks the ones before it
From the second milestone onward, the functional tests accumulated from all previous milestones run as a **regression suite** after the current milestone's own tests.
This is what keeps a long migration honest. Work landing in milestone 8 cannot quietly break behavior that was proven in milestone 2 without you hearing about it. A regression failure is surfaced rather than blocking, because the right fix may belong to either milestone — that is a judgement call, not something to automate.
### See a finished migration before connecting anything
There is now a **read-only sample project**: a real modernization, replayed end to end across twelve steps, reachable from the sign-in screen without connecting a repository.
Chat replays the actual conversation recorded during that migration, so you can see how the agent was directed rather than just the outcome. Nothing writes to any account.
It is the fastest way to judge fit — and the easiest thing to send to a colleague who wants to understand the product without starting a trial.
### Set up a project together
Project setup is now a shared activity rather than a solo one. Setup is held by one person at a time, and that person can **hand over to a teammate** — with the new owner notified by email.
This matters because onboarding often needs two kinds of knowledge that rarely sit with the same person: what the application does, and how it builds. Now the person who knows the build can take the build environment step and hand it back.
### Smaller things worth knowing
* **Validation that means something.** A `smoke` script is now part of validating your original application. A health check proves a process is listening; a smoke test proves the application works. Until one passes, a lifecycle is not treated as validated.
* **Database seeding is its own step.** A new `seed_db` script separates preparing data from starting the application, so Morph can restart your app without re-seeding it each time.
* **Closing a pull request finishes the milestone.** Closing a milestone's PR without merging now completes it. To get different code, use review chat or an ad hoc milestone rather than closing and hoping for a retry.
* **Copyable invite links.** Creating a user or invitation now gives you a link you can send directly.
* **Seat visibility.** The Members screen shows how many seats are in use, and tells you what to do when they are all taken instead of failing at the last step.
* **The Validation Hub works at every level**, including Low. There are no functional tests to show there, but your lifecycle results still tell you whether the application installs and builds.
### ModelDaemon pools
Self-hosted daemons are now organized into **pools**: shared groups of machines that serve one or more projects. A team's build capacity belongs to the team, so nobody waits on one specific person's machine.
Previously, each team member ran their own daemon and their own work was routed to it. That meant setting up a daemon before you could do anything on a self-hosted project, and your work stopped whenever your machine did.
Any member of your organization with access to a project can now run work on that project's pool, so most people never need to install anything. One person sets up the pool, and the whole team uses it.
If you already have self-hosted daemons, this migration has been done for you. Existing daemons were converted into pools automatically, with no change to how your projects behave — nothing to install, migrate, or reconfigure.
#### Add a machine, get more capacity
A pool can hold as many daemons as you want. Morph routes each piece of work to an available machine on its own, so you never assign jobs or think about which daemon runs what.
* Adding a daemon to a pool increases capacity for every project connected to it — you are not sizing capacity per project.
* One pool can serve several projects at once, so a single set of machines can back your whole modernization program.
* Each pool declares its operating system and architecture up front, so work only ever lands on a machine that can run it.
The practical effect: two teammates can run milestones on the same project at the same time, provided the pool has the machines to serve them.
#### Join a pool instead of building one
When you set up a self-hosted build environment, you now choose between **joining an existing pool** and creating a new one. The pool list shows each pool's scope, status, connected projects, and daemon count, so it's clear which one is the right home for your project.
For most people joining an existing pool, setup is finished at that point. If you're creating a new pool, Morph generates the exact install command for your platform — run it on the machine, then click **Verify & Continue** to confirm the daemon is connected.
#### See what your pool is doing
Your project's Roadmap sidebar now has a **Daemon pool** section showing how many machines are online, what is currently running on them, and a link to manage the pool.
Expand **See daemon list** to view each machine individually and what it's doing right now — `Idle` or `Busy`.
When every machine in a pool is occupied, Morph tells you the pool is full and to try again when a machine frees up, rather than silently queueing. Executions and chats also show which daemon is hosting the work.
#### Chat is never blocked by a busy pool
**Knowledge chat** and **Code Review chat** are exempt from pool capacity limits. Even when every machine is running a milestone, you can still open project knowledge or review code — the work that needs your attention is never gated behind the work that doesn't.
### Organizational Knowledge: automatic tagging and item-level import
Project artifacts — lifecycle scripts, dependencies, acceptance criteria, instructions, project configuration, and wikis — are now automatically tagged with their associated repositories as projects are set up. That makes them discoverable as organizational knowledge with no manual export step.
The **Organizational Knowledge** page gives you a centralized view of all knowledge across your organization, with filtering by repository and source project.
#### Import specific items, not everything
When creating a new project — or at any time afterward from the Roadmap sidebar — you can selectively import specific items from the organizational knowledge pool instead of importing all of it.
In the create project form, click **Manage** in the **Organizational Knowledge** section to open the knowledge transfer drawer, where you can browse, search, and filter available items by artifact type. At project creation the drawer offers instructions and wikis from across your organization, with the most relevant marked **Recommended**. Nothing is selected for you — you choose what to bring in.
The same drawer opens later from the Roadmap sidebar with **Import Knowledge**, this time showing the full pool. Relevant items are highlighted as **Recommended**, and items that already exist in the project surface a conflict step where you choose to replace, keep both, or skip.
## July 2026
This month introduces parallel milestone execution, collaborative review, per-user daemon routing, and upstream sync — making large migrations faster to deliver and easier to coordinate across teams.
### Parallel milestones
Milestones now declare dependencies on one another. When milestones are independent (no shared file dependencies), they can execute simultaneously — each on its own branch, each producing its own PR. Dependent milestones remain locked until their prerequisites merge.
This means faster delivery without sacrificing PR review boundaries. You still review and merge each milestone individually; the difference is that independent work no longer waits in a queue.
When a milestone merges while sibling branches are in progress, Morph detects whether those branches need to incorporate the new code and flags them as **Rebase Required**. Triggering the rebase is a single click — the agent handles the integration automatically.
### Collaborative review
Multiple team members can now review the same milestone at the same time. Each reviewer gets their own independent review chat session — conversations, issue triaging, and resolutions don't collide.
When one reviewer resolves an issue or the agent applies a fix, Morph propagates the workspace changes to other active reviewers so everyone sees the latest code state. Chat sessions are locked to one active user at a time to prevent conflicting agent instructions, but multiple reviewers can browse issues and code in parallel.
### Per-user ModelDaemon
For self-hosted daemon deployments, the routing model is now **one daemon per user** instead of one daemon per project. Each team member's daemon handles that user's work and runs one active job at a time — so multiple team members can work on the same project simultaneously without blocking each other.
The daemon reports its status in real time: **online**, **busy**, or **offline**. If your daemon is busy, new requests queue until the current job finishes.
### Upstream sync
Upstream sync is now fully available. When your team pushes changes to the repository's mainline during the migration, you can trigger an upstream sync to incorporate those changes. This creates a sync milestone, updates the project baseline, and rebases any in-progress milestone branches — all handled by the agent.
## June 2026
This month, we focused on making Morph more practical for real modernization work: stronger quality gates, more flexible project setup, smarter functional testing, better notifications, and expanded deployment options for restricted environments.
### Acceptance Criteria
Acceptance Criteria bring measurable, automated quality gates to your code modernization projects. Instead of relying solely on builds and tests passing, you can now define custom checks - like performance thresholds, code coverage targets, benchmark results, or any quantifiable standard - that are automatically enforced before code is merged.
Each Acceptance Criteria check is linked to your project's lifecycle scripts and captures a baseline from the original codebase. As modernization progresses, every milestone review automatically validates that the modernized code meets the same, or better, quality bar as the original. If a check does not pass, the pull request is flagged before merge.
To help you get started quickly, Morph can automatically discover relevant lifecycle scripts and suggested Acceptance Criteria based on your codebase's structure and testing patterns. You can also create and manage Acceptance Criteria manually through chat.
Acceptance Criteria are also visible during milestone review, so teams can see exactly which checks passed, which checks failed, and what needs attention before merge.
### Multiple projects per repository
You can now create multiple Morph projects from the same source repository. If you want separate modernization tracks, a maintenance project alongside an active migration, or different scopes on the same codebase.
Each project still runs on its own feature branches and milestones, so work stays isolated even when the underlying repository is shared.
When you create a project, the repo picker shows which other projects already use that repository, so you can make an informed choice. Morph handles setup efficiently behind the scenes, and removing one project will not disrupt another that shares the same source - your other projects, branches, and in-progress work stay intact.
### Functional testing improvements
Morph's functional testing workflows are now smarter across backend tests, frontend E2E tests, and projects where the application is already running.
#### Smarter backend functional tests
The backend testing agent now classifies features per endpoint rather than per repository when deciding what has pre-existing behavior to compare against. It also sets up reproducible test environments by seeding databases and running lifecycle scripts.
#### Frontend E2E test generation improvements
The frontend testing agent now detects and reuses existing Playwright suites in the target repository instead of scaffolding from scratch. It reuses the repository's existing authentication setup, defaults to mocked APIs for stability, and captures results even when tests fail.
#### Connect to a running application
Morph can now connect to an already-running application instead of managing the application lifecycle itself. The testing agent understands connect mode: it verifies connectivity without attempting to restart the app.
### Notifications
Morph now tells you when something is ready to review or input is needed. Five moments produce a notification:
* Your Project Spec is ready.
* Your Roadmap is generated.
* Your Lifecycle config is drafted.
* A milestone pull request is pending review.
* Morph is waiting for input
For each notification, you receive an email. If Morph is open in your browser, you also see an in-app banner in the top-right corner that takes you directly to the right project, milestone, or pull request.
### On-prem and air-gapped Morph platform support
Modelcode now supports on-premise and air-gapped deployment of the Morph platform in Amazon Web Services, AWS GovCloud (US), and Google Cloud Platform. This gives customers more control over their environment by enabling independent deployments through Terraform scripts and deployment documentation.
By removing dependencies on external cloud-hosted services like GitHub, Morph can support modernization workflows that need to run securely within isolated infrastructure.
The platform uses Kubernetes for orchestration and Gitea as a self-hosted Git provider to manage code repositories locally. This architecture supports critical operations such as pull requests, comments, and milestone agent executions entirely within the customer's network.
It also handles the orchestration needed to seed initial tenants, provision administrative users, and automate Docker image bundling to streamline installation in restricted environments.
### Gitea as an external provider
We've now added Gitea as a core Git provider, it adds support for customers who cannot use cloud-hosted platforms like GitHub because of network restrictions, compliance requirements, or air-gapped environments.
For these customers, Morph provides its own Gitea instance as the code-hosting layer, giving teams a fully functional Git workflow without requiring external connectivity.
## May 2026
### Multi-repo support is generally available
The Morph Platform now supports many-to-many modernization projects across multiple source repositories and multiple target repositories.
This is especially important for enterprise backend modernization projects where the application is spread across services, shared libraries, APIs, generated clients, and separate target applications.
**What changed**
* The Morph Platform can support many source repos to many target repos.
* Modernization projects can include multiple related codebases.
* Backend modernization workflows can better reflect real enterprise application structures.
**Why it matters**
Most enterprise systems do not live in one clean repository. Multi-repo support allows the Morph Platform to work across the actual shape of customer software instead of forcing teams to simplify their architecture before starting a modernization project.
***
### ModelDaemon
ModelDaemon introduces a more secure and scalable execution model for customer environments.
MD runs inside the customer’s infrastructure using outbound-only connectivity. the Morph Platform continues to orchestrate the work, while execution happens closer to the customer’s code, dependencies, tools, and internal systems.
**What changed**
* ModelDaemon runs inside the customer environment.
* Connectivity is outbound-only.
* The Morph Platform can execute work closer to private code, private dependencies, and internal infrastructure.
* The daemon now supports smarter execution through the `morph-agent` at the edge.
**Why it matters**
Customers do not need to expose inbound access or move private code and dependencies outside their environment. This makes the Morph Platform more practical for enterprise and regulated deployments.
***
### Smarter local execution with morph-agent
With ModelDaemon, the daemon is no longer just a remote command runner.
The `morph-agent` can run full LLM-driven and it allows the agent to reason through dependencies, make code changes, run commands, execute tests, and handle workflows directly inside the customer’s infrastructure.
**What changed**
* The daemon can run LLM-driven execution loops locally.
* Code changes, dependency handling, and workflow execution can happen inside the customer environment.
* The Morph Platform orchestration coordinates the work while the daemon performs richer local execution.
**Why it matters**
Enterprise projects often depend on internal services, private packages, local tooling, and environment-specific setup. Smarter local execution helps the Morph Platform operate in those environments with fewer assumptions.
***
### Distributed and scalable execution architecture
ModelDaemon also moves the Morph Platform toward a more distributed, async, event-driven execution architecture.
This replaces the older tightly coupled Docker-control model with a more flexible execution system based on parallel workspaces and event-driven coordination.
**What changed**
* Execution is now more async and event-driven.
* Parallel workspaces improve flexibility and scalability.
* The Morph Platform is less dependent on tightly coupled Docker control paths.
**Why it matters**
Large modernization projects need execution infrastructure that can handle long-running work, retries, partial progress, and customer-specific environments. This architecture gives the Morph Platform a stronger foundation for more complex projects.
***
### Improved ModelDaemon setup experience
The Morph Platform now provides a more continuous setup and execution flow for ModelDaemon projects.
Instead of requiring users to complete a rigid multi-step configuration process, the Morph Platform can analyze the repository, detect dependencies, identify missing metadata, and provide clearer next-step guidance during execution.
**What changed**
* Repo analysis is more integrated into setup.
* Dependency detection is clearer.
* Missing metadata is surfaced earlier.
* Execution progress is streamed with better guidance.
**Why it matters**
Modernization often starts with the hardest question: “How does this application actually run?” These improvements help the Morph Platform guide users through setup instead of requiring perfect configuration up front.
***
### Robust functional testing
The Morph Platform can validate parts of your application, such as APIs and services, and continue making progress even when some dependencies are missing.
**What changed**
* Missing dependencies no longer have to block all progress.
* The Morph Platform can continue useful work even when the full environment is incomplete.
**Why it matters**
Enterprise environments are rarely perfect on the first run. Partial execution helps teams avoid all-or-nothing failures and continue moving forward while missing dependencies are identified and resolved.
***
### Clearer errors and chat driven resolution
The Morph Platform now provides clearer explanations for configuration and lifecycle command errors.
For common setup issues, the Morph Platform can suggest a fix, apply it, and retry execution through chat.
**What changed**
* Configuration errors are easier to understand.
* Lifecycle command failures include clearer explanations.
* Common issues can be resolved with the Morph agent
* The Morph Platform will automatically retry execution after applying a fix.
**Why it matters**
Setup issues will still happen, especially in large enterprise applications. The goal is to make those issues less manual, less mysterious, and less likely to stop a project.
***
### Frontend modernization support
The Morph Platform now includes early support for frontend modernization workflows.
**Why it matters**
Many modernization projects are not purely backend. They include server-rendered templates, embedded frontend logic, and older UI frameworks that need to be separated from backend business logic. This release is the first step toward broader frontend stack support.
Frontend modernization support is currently limited and will continue expand as the Morph Platform evolves.
***
### Azure DevOps support
The Morph Platform now supports Azure DevOps.
This expands the environments where customers can connect the Morph Platform to existing source control and delivery workflows.
**What changed**
* Added Azure DevOps repository support.
* Enabled the Morph Platform project setup for Azure DevOps-based customers.
* Completed support for HealthEquity and RadarHealth workflows.
**Why it matters**
Many enterprise teams use Azure DevOps as their primary development platform. This update removes friction for customers who want to use the Morph Platform without changing their existing source control workflow.
***
For questions about a specific change, email [support@modelcode.ai](mailto:support@modelcode.ai).