Contrato de agent de OpenSpec
Interfaces legibles por máquina de la CLI openspec, verificadas con src/
(auditoría final, 2026-06-11). Cada estructura que sigue se ha documentado a
partir del código que la genera.
1. Convenciones generales
Sección titulada «1. Convenciones generales»- Un documento JSON por invocación. En modo
--json, stdout contiene exactamente un documento JSON (con sangría de 2 espacios). El texto para personas, los indicadores de progreso y el aviso de Store se escriben en stderr. - Aviso de Store. En modo normal, si se selecciona una raíz de Store, se escribe
Using OpenSpec root: <id> (<path>)en stderr. Nunca aparece en modo JSON. - Las mayúsculas de las claves dependen de la interfaz (consulta «Incoherencias conocidas»): los resultados de store/doctor/context usan
snake_case; los de flujo de trabajo (status,instructions,new change,validate,list) usancamelCase, salvo el objetorootincluido, que siempre usastore_id. - La mayoría de las claves opcionales se omiten en vez de tener valor null, por ejemplo,
root.store_idymember.path. Las excepciones que usannullexplícitamente se indican para cada estructura (los camposgit.*de store doctor y los resultados de error).
2. Envoltura de diagnósticos
Sección titulada «2. Envoltura de diagnósticos»Todos los diagnósticos legibles por máquina (StoreDiagnostic) comparten esta estructura:
{ "severity": "error" | "warning" | "info", "code": "snake_case_string", "message": "human sentence", "target": "dotted.surface (optional)", "fix": "one actionable sentence/command (optional)"}Los diagnósticos aparecen en dos lugares: en matrices de estado (status: StoreDiagnostic[], en el nivel superior o en cada elemento) para indicar problemas de estado, y como errores lanzados, que se convierten en una matriz status de un solo elemento cuando falla un comando.
3. Selección de la raíz y RootOutput
Sección titulada «3. Selección de la raíz y RootOutput»Todos los comandos que resuelven la raíz (list, show, validate, status, instructions, instructions apply, instructions archive, new change, archive, doctor, context, schemas) determinan una única raíz de OpenSpec mediante este orden de prioridad:
--store <id>→ la raíz del Store registrado (source: "store").- En su defecto, el ancestro más cercano con
openspec/: estructura de planificación →source: "nearest"(se ignora un punterostore:con un aviso en stderr); directorio que solo contiene configuración con un punterostore:válido → ese Store,source: "declared". - Sin raíz cercana y con
defaultStoreglobal configurado (openspec config set defaultStore <id>) → ese Store,source: "global_default"; un identificador obsoleto produce el error subyacente del Store y unfixconopenspec config unset defaultStore. - Sin raíz cercana ni valor predeterminado, pero con Stores registrados → error
no_root_with_registered_stores. - Sin raíz, valor predeterminado ni Stores: los comandos pueden tratar el directorio de trabajo actual como
source: "implicit"; en cambio,doctor,context,listyvalidatepor lotes fallan conno_openspec_root.listconserva el fallback implícito para proyectos antiguos conopenspec/project.md.
Los resultados JSON satisfactorios normalmente incluyen la raíz; schemas --json
sigue devolviendo deliberadamente la matriz sin envolver, por compatibilidad, tal como se documenta en §4.13:
"root": { "path": "/abs/path", "source": "store" | "declared" | "global_default" | "nearest" | "implicit", "store_id": "id (only when store-selected)" }Contrato de error de raíz: en modo JSON, si falla la resolución, se imprime { ...commandNullShape, "status": [diagnostic] } en stdout y se devuelve el código de salida 1.
4. Estructuras JSON de los comandos
Sección titulada «4. Estructuras JSON de los comandos»4.1 list --json
Sección titulada «4.1 list --json»{ "changes": [ { "name", "completedTasks", "totalTasks", "lastModified", "status": "no-tasks"|"complete"|"in-progress", "nested"?: ["<area>/<name>", ...] } ], "warnings"?: [ { "code", "name", "nested", "message" } ], "root": RootOutput } — en este caso, el campo status de cada cambio es un valor enumerado de tipo cadena. --specs: { "specs": [ { "id", "requirementCount" } ], "root" }.
warnings (omitido si está vacío) informa de los directorios de changes/ que
no son cambios. Actualmente, el único código es nested_change_directory: una
carpeta de espacio de nombres que contiene directorios de cambios, que OpenSpec
no puede abordar porque un cambio siempre debe ser un directorio directamente
bajo changes/. La misma entrada incluye nested en el cambio enumerado; en
ese caso, status no tiene significado. No trates esa entrada como un cambio:
informa del mensaje y deja los directorios tal como están.
4.2 show <item> --json
Sección titulada «4.2 show <item> --json»Change: { "id", "title", "deltaCount", "deltas": [...], "root" }. Spec: { "id", "title", "overview", "requirementCount", "requirements": [...], "metadata": { "version", "format", "sourcePath"? }, "root" }. Un requisito, en una especificación o en requirement/requirements de un delta de cambio, tiene la forma { "name", "text", "scenarios": [ { "name", "rawText" } ] }. El name de un requisito es su encabezado sin Requirement: ni la secuencia final de #, el nombre exacto con el que archive compara las entradas MODIFIED/REMOVED/RENAMED. El name de un escenario es su encabezado de nivel 4 sin Scenario: ni la secuencia final de #, el nombre que compara la comprobación de pérdida de escenarios MODIFIED.
4.3 validate --json
Sección titulada «4.3 validate --json»{ "items": [ { "id", "type": "change"|"spec", "valid", "issues": [ { "level", "path", "message", "line"?, "column"? } ], "durationMs" } ], "summary": { "totals": {items,passed,failed}, "byType": {...} }, "version": "1.0", "root" }. Devuelve el código de salida 1 si falla algún elemento.
4.4 status --json
Sección titulada «4.4 status --json»{ "changeName", "schemaName", "planningHome"?: { "kind", "root", "changesDir", "defaultSchema" }, "changeRoot", "artifactPaths": { "<id>": {outputPath, resolvedOutputPath, existingOutputPaths} }, "nextSteps": ["..."], "actionContext": { "mode": "repo-local", "sourceOfTruth": "repo", "planningArtifacts", "linkedContext", "allowedEditRoots", "requiresAffectedAreaSelection", "constraints" }, "isPlanningComplete", "isComplete", "applyRequires", "artifacts": [ {id, outputPath, status: "done"|"skipped"|"ready"|"blocked", requires, missingDeps?} ], "root" }. Para una raíz seleccionada mediante un almacén, allowedEditRoots es [<declaring project>, <store>] cuando el proyecto más cercano en la ruta actual es una raíz solo de configuración cuyo puntero store: apunta a ese almacén, y [<store>] en los demás casos (incluido un defaultStore global), con una restricción que indica al agent que pregunte en qué repositorio debe editar. OpenSpec no envía las tareas de un almacén a repositorios, así que el proyecto declarante es el actual, no todos los repositorios que toca el cambio. isPlanningComplete indica que existe cada artefacto de planificación que no se haya omitido; los omitidos se consideran satisfechos sin crearlos. No indica si se completaron las tareas de implementación. isComplete se conserva como alias de compatibilidad con el mismo valor. requires de cada artefacto contiene los ID de sus dependencias directas (siempre está presente, así que se pueden calcular todas las dependencias transitivas incluso cuando el artefacto está done); missingDeps solo aparece cuando está blocked. La matriz artifacts sigue el orden de dependencias. Si varios artefactos quedan listos al mismo tiempo, se respeta el orden en que aparecen en la declaración artifacts: del esquema (nunca el orden alfabético), así que la primera entrada ready indica qué artefacto escribir a continuación; missingDeps sigue ese mismo orden. "skipped" identifica un artefacto cuya ruta generates está bajo specs/ y cuyo cambio declara skip_specs: true en .openspec.yaml; satisface las dependencias, pero no se debe crear. Si no hay cambios activos: { "changes": [], "message", "root" }, código de salida 0.
--all (lote, incompatible con --change; combinarlos genera un error con la
estructura nula { "changes": [], "root": null, "status": [d] }): { "changes": [ <per-change status object, no per-change root>, ... ], "root" }, ordenado por nombre de cambio. Si no se puede cargar un cambio, su posición contiene
{ "changeName", "status": [d] }; el recorrido continúa, conserva el sobre
completo y devuelve 1 tanto en modo texto como JSON. Un --schema no válido
hace fallar toda la invocación con la estructura nula, incluso si no hay
cambios.
4.5 instructions <artifact> --json
Sección titulada «4.5 instructions <artifact> --json»{ "changeName", "artifactId", "schemaName", "changeDir", "planningHome"?, "outputPath", "resolvedOutputPath", "existingOutputPaths", "description", "instruction"?, "context"?, "rules"?, "references"?: ReferenceIndexEntry[], "skipped"?, "warning"?, "template", "dependencies": [{id,done,path,description,skipped?}], "unlocks", "root" }. unlocks enumera los artefactos que quedan listos al crear este, en el orden declarado por el esquema (el mismo que recomienda status). "skipped": true (junto con "warning") aparece cuando el cambio declara skip_specs: true y se omite este artefacto; no crees sus archivos. Una dependencia con skipped: true se considera satisfecha aunque no haya archivos; no intentes leer sus rutas.
ReferenceIndexEntry: { "store_id", "root"?, "specs"?: [{id,summary}], "fetch"?, "status": [] }: las entradas resueltas incluyen root/specs/fetch; las no resueltas contienen store_id y el estado de advertencia. El índice tiene un límite de 50 KB (reference_index_truncated).
4.6 instructions apply --json
Sección titulada «4.6 instructions apply --json»{ "changeName", "changeDir", "schemaName", "contextFiles": { "<artifactId>": ["/abs", ...] }, "progress": {total,complete,remaining}, "tasks": [{id,description,done}], "state": "blocked"|"all_done"|"ready", "missingArtifacts"?, "missingPrerequisites"?, "warnings"?, "instruction", "references"?, "context"?, "operationGuidance"?, "root" }. missingArtifacts indica qué bloquea apply (apply.requires del esquema); missingPrerequisites enumera, en el orden de creación, todo lo que aún debe prepararse antes de ejecutar apply: el cierre transitivo de esos requisitos, por lo que la lista puede ser más larga. warnings enumera problemas no bloqueantes del propio cambio; actualmente, un cambio listo para implementarse que no tenga especificaciones delta ni skip_specs: true, estado que openspec validate rechaza. Los dos campos opcionales de la raíz (context, operationGuidance) se leen en cada invocación desde la raíz seleccionada. context es una entrada obligatoria a nivel de prompt: se deben aplicar los datos, convenciones y restricciones pertinentes del proyecto. operationGuidance es una entrada orientativa cuyas recomendaciones solo se siguen cuando son aplicables y compatibles con el flujo integrado. Ambos campos se mantienen separados del estado, las tareas, el progreso, los archivos de contexto y las instrucciones integradas.
4.7 instructions archive --json
Sección titulada «4.7 instructions archive --json»{ "changeName", "context"?, "operationGuidance"?, "root" }. Requiere un
--change válido en la raíz resuelta del repositorio o del almacén y aplica
las mismas reglas de contexto obligatorio e indicaciones orientativas que
apply. Esta interfaz de entradas de ejecución es de solo lectura: no devuelve
el flujo estático de archivado, no inspecciona ni combina especificaciones
delta, no escribe las especificaciones principales ni mueve el cambio.
4.8 new change <name> --json
Sección titulada «4.8 new change <name> --json»Correcto: { "change": { "id", "path", "metadataPath", "schema" }, "root" }.
Error: { "change": null, "status": [d] }, código de salida 1.
4.9 archive <name> --json
Sección titulada «4.9 archive <name> --json»Correcto: { "archive": { "change", "archivedAs": "YYYY-MM-DD-name", "path", "specsUpdated", "totals"?, "warnings"? }, "root" }. Error: { "archive": null, "root"?, "status": [d] }, código de salida 1. specsUpdated es verdadero únicamente si se escribió o retiró al menos un archivo de especificación (si el cambio elimina el último requisito de una capacidad, se borra su especificación, lo que requiere retire_capabilities: true en .openspec.yaml; cada retirada aparece en warnings, con un comando de recuperación de Git listo para pegar solo si la especificación estaba en la copia de trabajo del invocador). Un cambio ya sincronizado se archiva con todos los totales en cero y los elementos omitidos en warnings. El modo JSON es estrictamente no interactivo: cada punto en que se haría un prompt devuelve un código archive_*.
archive: null: el comando falló. No garantiza que los archivos no hayan cambiado.archive_retirement_cleanup_failed: el cambio se archivó, pero falló la verificación de la copia de seguridad de la retirada o su limpieza. Es posible que una ruta de copia de seguridad indicada haya cambiado o desaparecido. El mensaje también puede informar de un origen preparado que quedó tras una limpieza fallida de la copia de fallback. Revisa el archivo actual y todas las rutas de recuperación indicadas antes de limpiar. Conserva el contenido necesario. Volver a ejecutar archive no limpia estas rutas.archive_error: el diagnóstico de fallback no indica si los archivos cambiaron. Revisa el cambio, el archivo y las especificaciones afectadas antes de reintentar.
4.10 doctor --json
Sección titulada «4.10 doctor --json»{ "root": { "path", "source", "store_id"?, "healthy", "status": [] }, "store": { "id", "metadata": {present,valid,remote?}, "origin_url"?, "drift"?: {ahead,behind}, "status": [] } | null, "references": [...], "status": [] }. drift (solo presente en copias de almacenes respaldadas por Git que tengan una referencia de seguimiento ascendente) contiene el número de commits adelantados o atrasados respecto de la última referencia ascendente obtenida, no del remoto en tiempo real. Los problemas de estado de cualquier gravedad devuelven el código 0. Resultado de error: { "root": null, "store": null, "references": [], "status": [d] }, código de salida 1.
4.11 context --json
Sección titulada «4.11 context --json»{ "root": { "path", "source", "store_id"?, "role": "openspec_root" }, "members": [ { "role": "referenced_store", "id", "path"?, "remote"?, "fetch"?, "status": [] } ], "status": [] }. Un miembro está AVAILABLE si existe su ruta Y su estado está vacío. --code-workspace <path> escribe {folders:[{name,path}]} (solo los almacenes referenciados disponibles, con prefijos ref:); en modo JSON, primero se escribe el archivo y luego se muestra la salida, de modo que stdout contiene exactamente un documento incluso si falla la escritura. Error: { "root": null, "members": [], "status": [d] }, código de salida 1.
4.12 store ... --json
Sección titulada «4.12 store ... --json»setup/register: { "store": {id, root, metadata_path?}, "registry": {path, registered, already_registered}, "git": {is_repository, initialized, committed}, "created_files": [], "status": [] }. unregister/remove: { "store", "registry": {path, removed}, "files": {deleted, deleted_path, left_on_disk}, "status": [] }. list: { "stores": [{id, root}], "status": [] }. doctor: { "stores": [ { id, root, metadata_path?, openspec_root: {...healthy, status}, metadata: {present, valid, id?, remote}, git: {is_repository, has_commits, has_uncommitted_changes, has_remote, origin_url}, status } ], "status": [] } (null = desconocido/no comprobado). Los problemas de estado devuelven el código 0; los errores, el código 1 y la estructura nula correspondiente. Si se cancela un prompt, se devuelve 130.
4.13 schemas --json / templates --json
Sección titulada «4.13 schemas --json / templates --json»schemas: la salida correcta sigue siendo una matriz sin envoltura [ {name, description, artifacts, source} ]; aplica el orden canónico de selección de la raíz y acepta --store <id>. Error al resolver la raíz: { "schemas": [], "root": null, "status": [d] }, código de salida 1. templates: objeto indexado por clave { "<artifactId>": {path, source} }, sigue dependiendo de cwd y no incluye claves root/status.
5. Exit-code contract
Sección titulada «5. Exit-code contract»| Situación | Salida | Stdout |
|---|---|---|
| Ejecución correcta, incluidos problemas de estado (doctor/context/store doctor) | 0 | La carga |
Error del comando en modo --json |
1 | Un documento JSON con status: [d] y la estructura nula del comando |
validate con elementos no válidos |
1 | Informe completo |
Cancelación de prompt (grupo store, modo para personas) |
130 | Solo stderr |
6. Diagnostic code catalog
Sección titulada «6. Diagnostic code catalog»Resolución
Sección titulada «Resolución»no_openspec_root, no_root_with_registered_stores, no_registered_stores, unknown_store, store_identity_mismatch, unhealthy_store_root, store_path_not_supported, invalid_store_pointer, initiative_option_removed, areas_option_removed; pass-through: invalid_store_id, invalid_store_registry, invalid_store_metadata.
Estado de la raíz de OpenSpec (error, sin solución)
Sección titulada «Estado de la raíz de OpenSpec (error, sin solución)»openspec_store_root_missing, openspec_store_root_not_directory, openspec_root_missing, openspec_root_not_directory, openspec_config_missing, openspec_config_not_file, openspec_specs_not_directory, openspec_changes_not_directory, openspec_archive_not_directory. During the stores beta, openspec/specs/, openspec/changes/, and openspec/changes/archive/ may be absent in a healthy root; they are only health errors when present but not directories.
Registro, identidad y estado de almacenes
Sección titulada «Registro, identidad y estado de almacenes»invalid_store_id, invalid_store_registry, invalid_store_metadata, store_registry_busy, store_not_found, no_store_registry, store_registry_changed, store_metadata_missing, store_metadata_id_mismatch, store_metadata_invalid, store_id_conflict, store_path_conflict, store_already_registered (info).
Configurar, registrar y eliminar almacenes
Sección titulada «Configurar, registrar y eliminar almacenes»store_setup_id_required, store_setup_path_required, store_setup_path_not_directory, store_setup_inside_git_repo, store_setup_non_empty_directory, store_setup_cancelled, store_path_required, store_path_missing, store_path_not_directory, store_root_pointer_declared, store_register_root_unhealthy, store_register_identity_confirmation_required, store_register_cancelled, store_remote_empty, store_remote_requires_hand_edit, store_remove_confirmation_required, store_remove_cancelled, store_remove_path_not_directory, store_remove_metadata_missing, store_remove_contains_registered_store, store_root_missing (warning in remove, error in doctor), store_root_not_directory.
Git del almacén
Sección titulada «Git del almacén»store_git_init_failed, store_git_identity_missing, store_git_commit_failed, store_git_no_commits (warning), store_clone_fragile_directories (warning), store_remote_divergence (info, doctor), store_checkout_drift (info, doctor).
Referencias (advertencia)
Sección titulada «Referencias (advertencia)»reference_invalid_id, reference_registry_unreadable, reference_unresolved, reference_root_unhealthy, reference_index_truncated.
Relaciones (advertencia; doctor; context solo conserva la del registro)
Sección titulada «Relaciones (advertencia; doctor; context solo conserva la del registro)»relationship_registry_unreadable, root_pointer_ignored, root_pointer_invalid, pointer_declarations_inert.
Archivado (modo JSON)
Sección titulada «Archivado (modo JSON)»archive_change_name_required, archive_change_not_found, archive_change_symlink, archive_validation_failed, archive_confirmation_required, archive_tasks_incomplete, archive_spec_update_failed, archive_spec_validation_failed, archive_target_exists, archive_retirement_cleanup_failed, archive_error.
Escrituras de contexto
Sección titulada «Escrituras de contexto»context_file_exists, context_output_dir_missing.
Fallbacks
Sección titulada «Fallbacks»doctor_failed, context_failed, store_error, change_error, archive_error.
Known inconsistencies
Sección titulada «Known inconsistencies»Registrado por la auditoría final; los cambios de nombres de claves publicadas son decisiones de producto aplazadas hasta después de esta versión:
En modoCorregido en la ronda final de pruebas: los elementos desconocidos o ambiguos de--json, algunas rutas de error solo escribían en stderr y no emitían un documento JSON.show/validategeneran{status:[{code: unknown_item | ambiguous_item, ...}]}; los errores lanzados enstatus/instructions/list/show/validatepasan por el asistente de errores compatible con JSON (estructura nula del comando +status);store <unknown subcommand> --jsongenera{status:[{code: unknown_store_subcommand}]};listincluye su estructura nula{changes|specs: [], root: null}si falla la resolución.store_root_missingse emite con dos niveles de gravedad (advertencia en remove, error en store doctor), según el contexto, como se documentó anteriormente.- Las claves de la familia store usan snake_case, mientras que las de la familia de flujos de trabajo usan camelCase;
root.store_idusa snake_case en todas partes. - En src existen cuatro declaraciones paralelas de tipos de sobre; los diagnósticos de archive nunca incluyen
target. list --jsonreutiliza la clavestatuscomo valor enumerado de tipo cadena para cada cambio.- Solo la salida de
validateincluye el campoversion. templatesignora la selección de la raíz (depende de cwd y no admite--store).- Las formas nominales obsoletas (subcomandos
change/spec) generan cargas sin envoltura, sinrootnistatus.
HagiCode
HagiCode es un espacio de programación con agentes. Las interacciones de interfaz, ricas y cómodas, hacen que planificar, ejecutar agentes y trabajar en proyectos sea accesible y fácil de seguir, para una experiencia de desarrollo atractiva.
Una experiencia de desarrollo atractiva gracias a interacciones de interfaz ricas y cómodas.
- InteligenteLos flujos de trabajo de OpenSpec convierten la intención en un itinerario ejecutable, de la propuesta al diseño, las tareas y la entrega.
- EficienteLa ejecución multiagente avanza en paralelo con la investigación, la implementación y la revisión, en varios repositorios y con los Agent CLI que ya usas.
- InteresanteLas interacciones de interfaz, ricas y cómodas, hacen que planificar, ejecutar agentes y trabajar en proyectos sea accesible y fácil de seguir.
Descargar para Windows
Compartir HagiCode
Convierte ideas en software entregado.
HagiCode es un espacio de trabajo de programación con agentes: los flujos de trabajo de OpenSpec planifican el cambio, la ejecución multiagente lo lleva a cabo y Hero Scenario hace visible el largo recorrido, para convertir ideas en software entregado.
- Inteligente
- Los flujos de OpenSpec convierten la intención en un camino de la propuesta a la entrega.
- Eficiente
- La ejecución multiagente avanza en paralelo con investigación, implementación y revisión.
- Divertido
- Las interacciones de interfaz facilitan la planificación, los agentes y el trabajo en proyectos.
© 2026 HagiCode | Powered By hagilight-starlight@0.21.0 | Branch: main | Commit: 54bf118 | Built:

