
Before you start: read about the original project in the article phpVirtualBox: manage VirtualBox from your browser.
In this series: Part 1: phpVirtualBox, Echo and Vue · Part 2: AI and OpenSpec · Part 3: implementation and tests
phpVirtualBox in Go series — part 2 of 3. A reliable migration starts with contracts and evidence, not with an automatic file conversion. In this part, we will organize the proposed reimplementation in Go, Echo, and Vue using AI and OpenSpec.
How to migrate with AI: behavior first, code later
The strategy I propose is incremental. Pin a commit of the reference project, record the lab environment, and ask the AI for a feature map. Each conclusion should point to files or documentation that support it. Where there is no evidence, the correct answer is a question to investigate, not an invented implementation.
A useful initial prompt would be:
Analise o phpVirtualBox sem modificar arquivos.
Mapeie telas, endpoints, autenticação, integração SOAP
e operações que alteram máquinas virtuais.
Para cada comportamento, indique os arquivos de referência.
Separe fatos verificados, dúvidas e propostas de melhoria.
Proponha um MVP somente leitura em Go + Echo + Vue.
Não implemente código e não execute ações em VMs.
The expected outcome is a feature matrix: what exists, what will be preserved, what will be left for later, and which tests will demonstrate compatibility. This avoids the trap of converting PHP files into Go files without understanding the rules they implement.
It is not mandatory to preserve every internal endpoint of the old interface. What is mandatory is deciding which behaviors and integrations must remain compatible. This decision must appear in the specification before it becomes code.
OpenSpec: turning the migration into reviewable changes
OpenSpec organizes work by changes with proposal, specifications, technical design, and tasks. The current documentation requires Node.js 20.19 or higher for the tool. In a separate repository for the new dashboard, preparation is:
npm install -g @fission-ai/openspec@1.14.1
openspec init
Select the integration with your assistant during initialization. The documented flow uses /opsx:explore, /opsx:propose, /opsx:apply and /opsx:archive; command spelling may vary depending on the assistant. They are assistant actions, not Bash commands. Official OpenSpec installation and workflow.
The first change could have this organization:
openspec/changes/painel-vms-somente-leitura/
├── proposal.md
├── design.md
├── specs/
│ └── inventario-vms/
│ └── spec.md
└── tasks.md
In the proposal, explain the objective and what will not be done. In the technical design, record how the API communicates with VirtualBox and how configurations and secrets will be handled. In the specifications, describe the observable outcomes. In the tasks, place small steps that can be implemented and verified.
Example specification for the first MVP
I would start with an authenticated dashboard, capable of listing machines without modifying the environment. The example below is a proposed specification for the new project, not an already implemented feature:
## ADDED Requirements
### Requirement: Inventário protegido de máquinas virtuais
The system SHALL listar apenas máquinas autorizadas
para o usuário autenticado, sem alterar seu estado.
#### Scenario: Consulta autorizada
- **WHEN** um usuário autorizado solicita o inventário
- **THEN** a API retorna UUID, nome e estado das máquinas
- **AND** nenhuma operação de escrita é executada
#### Scenario: Requisição sem autenticação
- **WHEN** uma requisição anônima consulta o inventário
- **THEN** a API responde HTTP 401
- **AND** não divulga dados das máquinas
#### Scenario: Usuário sem permissão
- **WHEN** um usuário autenticado não possui acesso ao inventário
- **THEN** a API responde HTTP 403
#### Scenario: Timeout do serviço de virtualização
- **WHEN** a consulta excede o prazo configurado
- **THEN** a API responde HTTP 504 com erro estruturado
- **AND** a interface permite uma nova tentativa manual
Note that each scenario requires evidence: HTTP response, fields returned, absence of writes, or interface behavior. “Works like the PHP” is too broad to be a useful acceptance criterion.
Example tasks.md: tasks that AI can execute
## 1. Referência e contrato
- [ ] Registrar o commit PHP usado como referência.
- [ ] Documentar o contrato GET /api/v1/vms e seus erros.
- [ ] Criar fixtures sanitizadas para os cenários aceitos.
## 2. Backend
- [ ] Criar a estrutura Echo com configuração externa.
- [ ] Implementar autenticação e autorização do inventário.
- [ ] Implementar a consulta SOAP com timeout configurável.
- [ ] Garantir liberação das sessões utilizadas, inclusive em erros.
- [ ] Testar host indisponível, acesso negado e resposta inválida.
## 3. Frontend e distribuição
- [ ] Exibir máquinas, lista vazia, carregamento e erros no Vue.
- [ ] Incorporar os arquivos compilados com go:embed.
- [ ] Executar o binário fora da árvore do código-fonte.
## 4. Aceitação
- [ ] Comparar o inventário com o host real de laboratório.
- [ ] Comprovar que a consulta não dispara operações de escrita.
- [ ] Registrar resultados dos testes e limitações conhecidas.
- [ ] Revisar a mudança antes de arquivar a especificação.
When working with the AI, ask only for the next task or a small set of dependent tasks. Require a summary of changed files, tests run, and limitations. The tool should not mark as complete an integration validated only with mocks if the criterion requires a real host.
OpenSpec organizes the process, but it does not replace review, testing, or domain knowledge. A checked box is not evidence of working.
How to split the work without losing control
A change should deliver an observable behavior. Instead of a task called “migrate the backend”, split authentication, inventory, operations, and persistence. Within each change, record dependencies: the inventory screen depends on a contract, but can be developed with a mocked server while the adapter is implemented.
If you use multiple agents, assign distinct files or modules and keep someone responsible for the shared contract. Don't let each agent invent its own error format or VM representation. Changes to the contract must go back to the specification and the tests, not arise silently during implementation.
A prompt for the execution phase:
Leia a proposta, o desenho técnico e os cenários desta mudança.
Implemente somente a próxima tarefa pendente autorizada.
Não altere o contrato para contornar um teste que falhou.
Não execute operações em infraestrutura de produção.
Adicione testes e registre os comandos e seus resultados.
Se faltar uma decisão, explique o bloqueio antes de inventá-la.
Só marque a tarefa concluída com evidência de aceitação.
Contract shared between specification, API, and interface
To keep the series consistent, the first MVP uses a single previously configured host. GET /api/v1/vms does not accept arbitrary SOAP address. The contract below is a project proposal, not an API already made available by phpVirtualBox:

| Scenario | Proposed response | Required evidence |
|---|---|---|
| Authorized query | 200, object with list vms. |
Only UUID, name, and state allowed; empty list is not an error. |
| Without authentication | 401. | No call to the SOAP adapter. |
| No permission | 403. | No call to the SOAP adapter and no exposed machine names. |
| Service unavailable | 502, stable error code. | Technical details sanitized only on the server. |
| Timeout exceeded | 504. | Cancellation/transport limits and release of acquired resources. |
Define an error envelope with code, message and request_id. The interface decides how to display the problem by the stable code, not by comparing translated phrases. Do not return credentials, raw XML, or stack traces. The HTTP codes above are choices of this new contract, not codes that the SOAP service promises to return.
Pin tools and validate artifacts
The installation above pins OpenSpec 1.14.1, version consulted in this review; also record the reference project commit, the Node version, and the output of openspec --version. The default profile includes explore, propose, apply, and archive; actions of the expanded flow depend on the chosen profile. In Codex, the documentation presents the family $openspec-propose, while other assistants use /opsx:propose. Follow what is already there openspec init install for your client.
openspec --version
openspec validate painel-vms-somente-leitura --strict --no-interactive
Validation checks the structure of the change; it does not run application tests or prove compatibility with VirtualBox. Do not mark “real host approved” just because the validator finished successfully.
Evidence that must accompany the review
- Reference commit and files that support each preserved behavior.
- Approved contract, rejection scenarios, and fixtures with no personal data or secrets.
- Test commands, result, and explicit distinction between simulation and real integration.
- VirtualBox version tested, service user, and known limits.
- List of what was not executed, without filling gaps with assumptions.
What it means to finish a change
The review needs to verify code, tests, and documentation together. Were the scenarios implemented? Are the errors still structured? Did any secret appear in fixtures? Was the behavior validated in the lab when required? A simulated test should not be presented as real integration with VirtualBox.
Archive the change only after the review and record the remaining limitations. In the next part, we'll see how this planning turns into a sequence of deliveries: from the first executable with embedded Vue to write, recovery, and deployment operations.
In this series: Part 1: phpVirtualBox, Echo and Vue · Part 2: AI and OpenSpec · Part 3: implementation and tests