> ## Documentation Index
> Fetch the complete documentation index at: https://docs.devin.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Workspaces e monorepos

> Configure o ambiente do Devin para monorepos, workspaces com vários pacotes e projetos com subdiretórios independentes.

Monorepos e workspaces com vários pacotes exigem cuidado extra em blueprints, porque diferentes subdiretórios podem usar linguagens, gerenciadores de pacotes ou conjuntos de dependências distintos. Devin oferece suporte a duas abordagens:

<CardGroup cols={2}>
  <Card title="Workspaces nativos (recomendado)" icon="cubes" href="#native-workspaces">
    Crie um blueprint separado para cada subdiretório. Cada workspace recebe suas próprias seções initialize, maintenance e knowledge, com o diretório de trabalho definido automaticamente para o subdiretório.
  </Card>

  <Card title="Subshells" icon="terminal" href="#subshells">
    Execute comandos em subdiretórios dentro de um único blueprint usando `(cd dir && command)`. Mais simples para monorepos pequenos com apenas alguns pacotes.
  </Card>
</CardGroup>

***

<div id="native-workspaces">
  ## Workspaces nativos
</div>

<Info>
  **Recomendado para a maioria dos monorepos.** Workspaces nativos dão a cada subdiretório seu próprio blueprint, com configuração, Knowledge e diretório de trabalho isolados. Isso é mais organizado e mais fácil de manter do que usar subshells à medida que o número de pacotes cresce.
</Info>

Com workspaces nativos, cada subdiretório recebe um blueprint dedicado. Os comandos nesse blueprint são executados com o diretório de trabalho já definido para o subdiretório — não é necessário usar `cd` nem subshells.

<div id="the-root-blueprint">
  ### O blueprint raiz
</div>

Todo repositório que usa workspaces nativos deve ter um **blueprint raiz**. O blueprint raiz é executado a partir da raiz do repositório e **antes** de qualquer blueprint com escopo de workspace. Use-o para configurações compartilhadas que se aplicam a todo o repositório — como instalar runtimes, ferramentas globais ou executar instalações de dependências na raiz.

```yaml theme={null}
# Blueprint raiz — executado primeiro, a partir da raiz do repositório
initialize: |
  npm install -g pnpm

maintenance: |
  pnpm install
```

Os blueprints de workspace então cuidam da configuração específica do pacote e são executados depois que o blueprint raiz é concluído.

<div id="creating-a-workspace">
  ### Como criar um workspace
</div>

1. Vá para **Configurações > Ambiente > Blueprints**
2. Clique no repositório
3. Clique em **Add workspace**
4. Insira o caminho do subdiretório (por exemplo, `packages/frontend`)
5. Defina o blueprint para esse workspace

<Warning>
  O caminho do workspace deve corresponder a um diretório real dentro do repositório. Se o caminho não existir quando o build for executado, o build falhará. Verifique se o caminho corresponde exatamente à estrutura do seu repositório (por exemplo, `packages/frontend`, não `pkg/frontend`).
</Warning>

<div id="example">
  ### Exemplo
</div>

Um monorepo com frontend em React e backend em Python. O blueprint raiz instala ferramentas compartilhadas, e cada workspace gerencia as próprias dependências:

<Tabs>
  <Tab title="Raiz">
    ```yaml theme={null}
    # Blueprint raiz — configuração compartilhada para todo o repo
    initialize: |
      npm install -g pnpm
      curl -LsSf https://astral.sh/uv/install.sh | sh

    knowledge:
      - name: structure
        contents: |
          Monorepo com dois packages:
          - packages/frontend — app React (TypeScript, pnpm)
          - packages/backend — API Python (FastAPI, uv)
    ```
  </Tab>

  <Tab title="packages/frontend">
    ```yaml theme={null}
    # Workspace com escopo em packages/frontend
    maintenance: |
      pnpm install

    knowledge:
      - name: lint
        contents: pnpm lint
      - name: test
        contents: pnpm test
      - name: dev
        contents: pnpm dev
    ```
  </Tab>

  <Tab title="packages/backend">
    ```yaml theme={null}
    # Workspace com escopo em packages/backend
    maintenance: |
      uv sync

    knowledge:
      - name: lint
        contents: uv run ruff check .
      - name: test
        contents: uv run pytest
      - name: dev
        contents: uv run uvicorn app.main:app --reload
    ```
  </Tab>
</Tabs>

As entradas de `knowledge` de cada workspace são limitadas a esse subdiretório. Quando Devin trabalha em `packages/frontend`, ele vê os comandos de lint/test/dev do frontend — não os do backend.

<div id="when-to-use-native-workspaces">
  ### Quando usar workspaces nativos
</div>

* Os subdiretórios têm **linguagens ou gerenciadores de pacotes diferentes**
* Cada pacote precisa de suas próprias **entradas do Knowledge** (comandos de lint, teste e build)
* Você quer uma **configuração isolada** — um blueprint com problema em um workspace não bloqueia os demais
* O número de pacotes está crescendo, e um único blueprint está ficando difícil de manter

***

<div id="subshells">
  ## Subshells
</div>

Para monorepos mais simples, você pode gerenciar tudo em um único blueprint usando subshells. Coloque os comandos entre parênteses para executá-los em um subdiretório sem afetar as etapas seguintes:

```yaml theme={null}
maintenance:
  - name: Frontend deps
    run: (cd packages/frontend && pnpm install)
  - name: Backend deps
    run: (cd packages/backend && uv sync)
```

Os parênteses `(cd ... && ...)` criam uma subshell. Quando a subshell é encerrada, o diretório de trabalho volta para a raiz do repositório na próxima etapa.

<Warning>
  Sem parênteses, `cd` altera o diretório de trabalho de todas as etapas subsequentes. Sempre use subshells ao alternar diretórios em etapas de blueprint.
</Warning>

<div id="why-subshells-matter">
  ### Por que os subshells são importantes
</div>

Compare estas duas abordagens:

<Tabs>
  <Tab title="Correto (subshells)">
    ```yaml theme={null}
    maintenance:
      - name: Frontend deps
        run: (cd packages/frontend && pnpm install)
      - name: Backend deps
        run: (cd packages/backend && uv sync)
    ```

    Cada etapa é executada a partir da raiz do repositório. Ambos os comandos encontram o subdiretório `packages/` correto.
  </Tab>

  <Tab title="Incorreto (sem subshells)">
    ```yaml theme={null}
    maintenance:
      - name: Frontend deps
        run: cd packages/frontend && pnpm install
      - name: Backend deps
        run: cd packages/backend && uv sync
    ```

    A primeira etapa muda o diretório de trabalho para `packages/frontend`. Em seguida, a segunda etapa tenta executar `cd packages/backend` tendo `packages/frontend` como base, o que falha.
  </Tab>
</Tabs>

<div id="when-to-use-subshells">
  ### Quando usar subshells
</div>

* O monorepo tem **alguns pacotes** com configuração simples
* Todos os pacotes usam a **mesma linguagem e o mesmo gerenciador de pacotes**
* Você não precisa de entradas de Knowledge para cada pacote

***

<div id="knowledge-entries-for-monorepos">
  ## Entradas de Knowledge para monorepos
</div>

Se você usa workspaces nativos ou subshells, entradas de Knowledge bem estruturadas ajudam Devin a navegar pela base de código:

```yaml theme={null}
knowledge:
  - name: structure
    contents: |
      This is a monorepo with three packages:
      - `packages/frontend` — React app (TypeScript, pnpm)
      - `packages/backend` — Python API (FastAPI, uv)
      - `packages/shared` — Shared TypeScript utilities
  - name: frontend
    contents: |
      cd packages/frontend
      Dev server: pnpm dev
      Lint: pnpm lint
      Test: pnpm test
  - name: backend
    contents: |
      cd packages/backend
      Dev server: uv run uvicorn app.main:app --reload
      Lint: uv run ruff check .
      Test: uv run pytest
```

<Tip>
  Uma entrada `structure` do Knowledge que mapeia cada diretório para sua linguagem e toolchain ajuda o Devin a navegar pelo repo rapidamente. Com workspaces nativos, cada workspace tem suas próprias entradas do Knowledge, então a entrada `structure` é mais útil no blueprint raiz ou em configurações baseadas em subshell.
</Tip>

<div id="examples">
  ## Exemplos
</div>

<div id="turborepo-nx-workspace">
  ### Turborepo / Nx workspace
</div>

Para workspaces gerenciados por uma ferramenta de build de monorepo, como Turborepo ou Nx, instale as dependências na raiz e deixe a ferramenta cuidar da orquestração de cada pacote:

```yaml theme={null}
initialize: |
  npm install -g pnpm turbo

maintenance: |
  pnpm install

knowledge:
  - name: structure
    contents: |
      Turborepo monorepo. Use `turbo` for building and testing:
      - `apps/web` — Next.js app
      - `apps/api` — Express API
      - `packages/ui` — Shared component library
      - `packages/config` — Shared configuration
  - name: build
    contents: turbo run build
  - name: test
    contents: turbo run test
  - name: lint
    contents: turbo run lint
  - name: dev
    contents: turbo run dev
```

<div id="multiple-jdk-versions">
  ### Múltiplas versões do JDK
</div>

Um monorepo Java em que diferentes serviços exigem diferentes versões do JDK:

```yaml theme={null}
initialize:
  - name: Install JDK 17 (primary)
    run: |
      sudo apt-get update -qq
      sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq openjdk-17-jdk-headless
      echo 'export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64' \
        | sudo tee /etc/profile.d/java.sh > /dev/null

  - name: Install JDK 11 (legacy service)
    run: |
      sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq openjdk-11-jdk-headless

maintenance:
  - name: Warm dependency caches
    run: |
      export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64
      (cd services/api && ./gradlew dependencies --refresh-dependencies)

      export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64
      (cd services/legacy && ./gradlew dependencies --refresh-dependencies)

knowledge:
  - name: build_api
    contents: |
      Build the API service (JDK 17):
        JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 \
        cd services/api && ./gradlew clean build
  - name: build_legacy
    contents: |
      Build the legacy service (JDK 11):
        JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64 \
        cd services/legacy && ./gradlew clean build
  - name: test_all
    contents: |
      Run tests for all services:
        JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 \
        (cd services/api && ./gradlew test)

        JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64 \
        (cd services/legacy && ./gradlew test)
```

<div id="org-blueprint-for-shared-tools">
  ### Blueprint da organização para ferramentas compartilhadas
</div>

Quando vários pacotes em um monorepo compartilham as mesmas ferramentas, instale-as uma única vez no blueprint de nível da organização:

```yaml theme={null}
# Blueprint nível da organização (Configurações > Environment > Blueprints > Org-wide setup)
initialize:
  - name: Install pnpm
    run: npm install -g pnpm
  - name: Install uv
    run: curl -LsSf https://astral.sh/uv/install.sh | sh
  - name: Install shared build tools
    run: npm install -g turbo typescript
```

Então, cada blueprint do repositório só precisa de comandos específicos do projeto:

```yaml theme={null}
# Repo blueprint (usa pnpm e uv do org blueprint)
maintenance:
  - name: Install all workspace deps
    run: pnpm install
  - name: Install Python service deps
    run: (cd services/ml-pipeline && uv sync)
```

<div id="best-practices">
  ## Boas práticas
</div>

<AccordionGroup>
  <Accordion title="Prefira workspaces nativos para monorepos complexos">
    Quando cada subdiretório tem sua própria linguagem, gerenciador de pacotes ou processo de build, workspaces nativos mantêm cada blueprint focado e independente. Reserve subshells para casos simples com poucos pacotes.
  </Accordion>

  <Accordion title="Sempre use subshells para trocar de diretório">
    Ao usar a abordagem com subshell, coloque os comandos `cd` entre parênteses: `(cd dir && command)`. Isso evita que a troca de diretório de uma etapa afete a próxima.
  </Accordion>

  <Accordion title="Coloque as ferramentas compartilhadas no blueprint da organização">
    Runtimes de linguagem e gerenciadores de pacotes usados em vários repositórios devem ficar no blueprint de nível da organização. Isso evita duplicação e mantém os blueprints do repositório focados na configuração específica do projeto.
  </Accordion>

  <Accordion title="Ordene as etapas de maintenance por dependência">
    Se o pacote A depende de que o pacote B tenha o build concluído primeiro, liste a etapa de build de B antes da etapa de instalação de A em `maintenance`. As etapas do blueprint são executadas sequencialmente na ordem em que aparecem.
  </Accordion>

  <Accordion title="Adicione uma entrada de Knowledge sobre a estrutura">
    Uma entrada de Knowledge chamada `structure`, que mapeia diretórios para suas linguagens e ferramentas, ajuda Devin a navegar pela base de código. Inclua qual gerenciador de pacotes cada subdiretório usa e quaisquer dependências entre pacotes.
  </Accordion>

  <Accordion title="Use entradas de Knowledge por pacote">
    Em vez de criar uma única entrada de Knowledge grande, crie entradas separadas para cada pacote (por exemplo, `frontend`, `backend`, `ml-pipeline`). Com workspaces nativos, cada workspace já inclui sua própria seção de conhecimento.
  </Accordion>

  <Accordion title="Mantenha o maintenance incremental">
    Use `pnpm install` (não `pnpm install --force`) e `uv sync` (não `rm -rf .venv && uv sync`). Comandos incrementais são mais rápidos durante rebuilds periódicos.
  </Accordion>
</AccordionGroup>

<div id="related-pages">
  ## Páginas relacionadas
</div>

* [Configuração declarativa de ambiente](/pt-BR/onboard-devin/environment/blueprints)
* [Referência de blueprints](/pt-BR/onboard-devin/environment/blueprint-reference)
* [Biblioteca de templates](/pt-BR/onboard-devin/environment/templates) — inclui templates de monorepo prontos para usar
