Registro público
Informe de salud del softwareesquema 0.27.0 · métricas 1.13.0 · 2026-07-23 15:01 UTC

shipeasy-ai / shipeasy

Shipeasy Claude Code plugin marketplace

TypeScriptSin licencia detectada★ 0 estrellas⑂ 0 forksdesde may 2026Ver en GitHub ↗

shipeasy-ai/shipeasy tiene un índice de salud de 40 sobre 100, lo que lo sitúa en la banda En riesgo. Su puntuación más alta es Engineering Quality (66/100) y la más baja, Security (24/100). Se actualizó por última vez hoy.

40
global / 100
En riesgo

Índice de salud del software

Las métricas se agrupan en categorías ponderadas sobre una escala de 1 a 100. El resultado global parte de su media; cuando la evidencia pública activa la Política de Jurisdicciones de Alto Riesgo, la calificación se ajusta y recibe el límite 49 (En riesgo). Preparación para IA queda fuera.

40
Excelente85-100Ejemplar; cumple prácticamente todos los criterios evaluados
Bueno70-84Saludable; carencias menores
Moderado50-69Aceptable con carencias notables; se recomienda revisión
En riesgo30-49Debilidades significativas; su adopción exige cautela
Crítico1-29Problemas graves (proyecto abandonado, un solo mantenedor, sin higiene)
VitalidadComunidad yAdopciónSostenibilidady GobernanzaCalidad deIngenieríaSeguridadPreparaciónpara IA

Perfil de puntuación

Cada eje es una categoría. La forma importa más que la media: un proyecto sano llena toda la figura, mientras que un perfil de picos y cráteres indica que la fortaleza en una dimensión enmascara el riesgo en otra.

Titularidad

shipeasy.aiOrganización
1 seguidor9 repositorios públicosdesde abr 2026

Este repositorio está respaldado por una organización: una custodia compartida y responsable que puede sobrevivir a cualquier mantenedor individual.

Ecosistemas de paquetes

Métricas por categoría

Vitalidad

¿Está vivo el proyecto: se escribe código y se publican versiones?

39En riesgo · 22% del índice global
Cómo se puntúa
36/36Recencia de push — último push hace 0 días
9.7/36Cadencia de commits — 14/52 semanas con commits
18/18Volumen de commits — 512 commits en el último año
0/10OpenSSF Scorecard: Maintained — project was created within the last 90 days. Please review its contents carefully
Datos de entrada utilizados
commits_last_year512
human_commit_share1
days_since_last_push0
active_weeks_last_year14
Cómo se puntúa
0/27Publica versiones — sin versiones publicadas
0/36Recencia de las versiones — sin versiones
0/27Cadencia de publicación — sin versiones
0/10OpenSSF Scorecard: Signed-Releases — sin datos
Datos de entrada utilizados
releases_count0
Excluidos de la puntuación (sin datos o no aplicable): OpenSSF Scorecard: Signed-Releases. Los pesos restantes se han renormalizado.

Comunidad y Adopción

¿Tiene el proyecto usuarios, descargas, atención y unas condiciones acogedoras para quienes contribuyen?

25Crítico · 18% del índice global
Cómo se puntúa
0/60Estrellas — 0 estrellas
0/25Forks — 0 forks
0/15Observadores — 0 observadores
Datos de entrada utilizados
forks0
stars0
watchers0
growth_stateunverified
growth_factor_pct100
growth_unverified_reasonno_history
Cómo se puntúa
22.5/22.5README
0/22.5Licencia — no se detectó ningún archivo de licencia
0/18Guía CONTRIBUTING
0/13.5Código de conducta
0/7.2Plantilla de issues
0/6.3Plantilla de PR
Datos de entrada utilizados
has_readme
has_licenseno
has_contributingno
has_issue_templateno
has_code_of_conductno
has_pull_request_templateno
Cómo se puntúa
50.6/80Descargas mensuales — 6259 descargas/mes en npm
0/20Dependientes en el registro — no lo informa este ecosistema
Datos de entrada utilizados
packages@shipeasy/cli, @shipeasy/mcp, @shipeasy/openapi
dependents
ecosystemsnpm
total_downloads
monthly_downloads6259
Excluidos de la puntuación (sin datos o no aplicable): Dependientes en el registro. Los pesos restantes se han renormalizado.

Sostenibilidad y Gobernanza

¿Sobrevivirá el proyecto a sus personas: factor bus, capacidad de respuesta, quién lo respalda y mantenimiento del paquete?

43En riesgo · 24% del índice global
Cómo se puntúa
0/46.8Resolución de issues — sin issues o sin datos
0/38.3Aceptación de PR — sin PR decididos o sin datos
0/15OpenSSF Scorecard: Code-Review — Found 0/30 approved changesets -- score normalized to 0
Datos de entrada utilizados
merged_prs0
open_issues0
closed_issues0
issue_closed_ratio
closed_unmerged_prs0
Excluidos de la puntuación (sin datos o no aplicable): Resolución de issues, Aceptación de PR. Los pesos restantes se han renormalizado.
Cómo se puntúa
30/30Respaldo de la propiedad — propiedad de una organización
0/20Dominio verificado
2.2/25Alcance del propietario — 1 seguidores de shipeasy-ai
7.8/25Trayectoria — 9 repos públicos, cuenta de ~0 años
Datos de entrada utilizados
followers1
owner_typeOrganization
is_verified
owner_loginshipeasy-ai
public_repos9
account_age_days87
Cómo se puntúa
25/25Publicado y resoluble — 3 paquete(s) en npm
35/35Recencia de publicación — última publicación hace 2 días
20/20Historial de versiones — 24 versiones en el registro
20/20No obsoleto — activo, ni obsoleto ni retirado
Datos de entrada utilizados
packages@shipeasy/cli, @shipeasy/mcp, @shipeasy/openapi
ecosystemsnpm
any_deprecatedno
min_days_since_publish2

Calidad de Ingeniería

¿Existen unas prácticas mínimas de ingeniería y documentación?

66Moderado · 20% del índice global
Cómo se puntúa
24/24Flujos de trabajo de CI — 11 flujo(s) de trabajo
24/24Pruebas presentes
0/16Configuración de linter
0/9.6Hooks de pre-commit
0/6.4.editorconfig
0/20OpenSSF Scorecard: CI-Tests — sin datos
Datos de entrada utilizados
has_ci
has_tests
has_editorconfigno
has_linter_configno
has_precommit_configno
Excluidos de la puntuación (sin datos o no aplicable): OpenSSF Scorecard: CI-Tests. Los pesos restantes se han renormalizado.
Cómo se puntúa
30/30README
25/25Directorio de documentación
0/15Sitio de documentación / página del proyecto
10/10Descripción del repositorio
0/10Topics
10/10Wiki
Datos de entrada utilizados
topics
has_wiki
homepage
has_readme
has_docs_dir
has_description

Seguridad

¿Son sólidas las prácticas visibles de seguridad y de cadena de suministro, sin exposición jurisdiccional de alto riesgo sin resolver?

24Crítico · 16% del índice global
Cómo se puntúa
7.5/7.5Binary-Artifacts — no binaries found in the repo
0/7.5Branch-Protection — branch protection not enabled on development/release branches
0/2.5CI-Tests — sin datos
0/2.5CII-Best-Practices — no effort to earn an OpenSSF best practices badge detected
0/7.5Code-Review — Found 0/30 approved changesets -- score normalized to 0
0/2.5Contributors — project has 0 contributing companies or organizations -- score normalized to 0
10/10Dangerous-Workflow — no dangerous workflow patterns detected
0/7.5Dependency-Update-Tool — no update tool detected
0/5Fuzzing — project is not fuzzed
0/2.5Licencia — license file not detected
0/7.5Maintained — project was created within the last 90 days. Please review its contents carefully
5/5Packaging — packaging workflow detected
0/5Pinned-Dependencies — dependency not pinned by hash detected -- score normalized to 0
0/5SAST — no SAST tool detected
0/5Security-Policy — security policy file not detected
0/7.5Signed-Releases — sin datos
0/7.5Token-Permissions — detected GitHub workflow tokens with excessive permissions
0/7.5Vulnerabilities — 10 existing vulnerabilities detected
Datos de entrada utilizados
sourceopenssf_scorecard
checks_evaluated16
scorecard_versionv5.5.0
checks_inconclusive2
scorecard_aggregate2,4
Excluidos de la puntuación (sin datos o no aplicable): ci_tests, signed_releases. Los pesos restantes se han renormalizado.

Preparación para IA

¿Hasta qué punto está el repositorio preparado para desarrollarse y mantenerse con agentes de codificación de IA? Es una insignia independiente y experimental — peso 0,0, de modo que se presenta por separado y no afecta a la puntuación de salud global.

57Moderado · 0% del índice global
Cómo se puntúa
0/45Instrucciones para agentes — sin CLAUDE.md / AGENTS.md / reglas de editor
0/15Documentación legible por máquinas (llms.txt)
40/40Historial de commits legible — 100 de 100 commits humanos declaran su intención (asunto estructurado o cuerpo explicativo)
Datos de entrada utilizados
has_llms_txtno
legible_history_share1
agent_instruction_files
agent_instruction_max_bytes
Cómo se puntúa
0/18Arranque con un solo comando
22/22Pruebas automatizadas
0/11Configuración de lint / formato
11/11Verificación estática de tipos — cli/tsconfig.json, mcp/tsconfig.json, openapi/tsconfig.json, skills-contract/tsconfig.json, skills-eval/tsconfig.json
10/10Entorno reproducible — lockfile
10/10Práctica demostrada con agentes — 98 de los últimos 100 commits con autoría o crédito de agente
0/8Mantenimiento automatizado — no se observan actualizaciones automáticas de dependencias
0/10OpenSSF Scorecard: Pinned-Dependencies — dependency not pinned by hash detected -- score normalized to 0
Datos de entrada utilizados
has_nixno
has_tests
lockfilespnpm-lock.yaml
has_dockerfileno
typed_language
bootstrap_files
has_devcontainerno
has_linter_configno
typecheck_configscli/tsconfig.json, mcp/tsconfig.json, openapi/tsconfig.json, skills-contract/tsconfig.json, skills-eval/tsconfig.json
agent_commit_share0,98
toolchain_manifests
dependency_bot_commit_share0
Cómo se puntúa
45/45Código verificable por tipos — TypeScript (tipado estático)
54.3/55Tamaños de archivo manejables — 2/156 archivos fuente de más de 60 KB
Datos de entrada utilizados
primary_languageTypeScript
largest_source_bytes176.624
source_files_sampled156
oversized_source_files2
Cómo se puntúa
40/40Esquema de API (OpenAPI/GraphQL/proto) — openapi/openapi.json, openapi/openapi.yaml, openapi/spec/openapi.yaml
20/20Servidor MCP
0/40Ejemplos ejecutables
Datos de entrada utilizados
example_dirs
has_mcp_signal
api_schema_filesopenapi/openapi.json, openapi/openapi.yaml, openapi/spec/openapi.yaml

Datos clave

0estrellas de GitHub
-contribuidores
512commits en los últimos 12 meses
0días desde el último push
0versiones publicadas
-factor bus
0issues abiertas
npmecosistemas de paquetes

Advertencias de recopilación de datos

  • Contributor list unavailable
  • GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository
  • deps.dev does not index npm:@shipeasy/cli@2.7.0; advisories assessed against the repository dependency graph instead

Más detalle

OpenSSF Scorecard 2.4 / 10
2.4agregado

Evaluación de seguridad independiente y agnóstica en cuanto a herramientas, procedente del proyecto de código abierto OpenSSF Scorecard. Cada comprobación premia una práctica de seguridad, no la herramienta de un proveedor concreto. Las comprobaciones que Scorecard no pudo determinar se marcan como n/d y se excluyen de la puntuación de seguridad (nunca se cuentan como cero).Scorecard v5.5.0 · 2026-07-23 15:01 UTC

10Binary-Artifactsno binaries found in the repo
0Branch-Protectionbranch protection not enabled on development/release branches
n/dCI-Testsno pull request found
0CII-Best-Practicesno effort to earn an OpenSSF best practices badge detected
0Code-ReviewFound 0/30 approved changesets -- score normalized to 0
0Contributorsproject has 0 contributing companies or organizations -- score normalized to 0
10Dangerous-Workflowno dangerous workflow patterns detected
0Dependency-Update-Toolno update tool detected
0Fuzzingproject is not fuzzed
0Licenselicense file not detected
0Maintainedproject was created within the last 90 days. Please review its contents carefully
10Packagingpackaging workflow detected
0Pinned-Dependenciesdependency not pinned by hash detected -- score normalized to 0
0SASTno SAST tool detected
0Security-Policysecurity policy file not detected
n/dSigned-Releasesno releases found
0Token-Permissionsdetected GitHub workflow tokens with excessive permissions
0Vulnerabilities10 existing vulnerabilities detected
Dependencias directas 23
RegistroPaqueteRestricción de versiónManifiesto
npm@babel/parser^7.29.0cli/package.json
npm@babel/traverse^7.29.0cli/package.json
npm@babel/types^7.29.0cli/package.json
npm@shipeasy/openapiworkspace:^2.1.0cli/package.json
npmchalk^5.3.0cli/package.json
npmcli-table3^0.6.5cli/package.json
npmcommander^12.1.0cli/package.json
npmconf^13.0.0cli/package.json
npmopen^10.1.0cli/package.json
npmora^8.1.0cli/package.json
npmpackage-manager-detector^1.6.0cli/package.json
npmprompts^2.4.2cli/package.json
npmtypescript^5.7.4cli/package.json
npmzod^4.0.0cli/package.json
npm@modelcontextprotocol/sdk^1.29.0mcp/package.json
npm@shipeasy/openapiworkspace:^2.3.0mcp/package.json
npmpackage-manager-detector^1.6.0mcp/package.json
npmtypescript^5.7.4mcp/package.json
npmzod^4.0.0mcp/package.json
npmzod^4.0.0openapi/package.json
npm@shipeasy/cliworkspace:*skills-contract/package.json
npm@shipeasy/mcpworkspace:*skills-contract/package.json
npm@shipeasy/sdk^7.7.0skills-contract/package.json
Todas las dependencias no recopilado

No fue posible recopilar el conjunto de dependencias resuelto para este informe: GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository

Informe JSON sin procesar legible por máquina
{
  "data": {
    "repo": {
      "topics": [],
      "is_fork": false,
      "size_kb": 10833,
      "has_wiki": true,
      "homepage": null,
      "languages": {
        "Shell": 10106,
        "JavaScript": 209589,
        "TypeScript": 1907156
      },
      "pushed_at": "2026-07-22T23:58:57Z",
      "created_at": "2026-05-12T20:00:20Z",
      "owner_type": "Organization",
      "updated_at": "2026-07-22T23:59:02Z",
      "description": "Shipeasy Claude Code plugin marketplace",
      "is_archived": false,
      "is_disabled": false,
      "license_spdx": null,
      "default_branch": "main",
      "license_spdx_raw": null,
      "primary_language": "TypeScript",
      "significant_languages": [
        "TypeScript"
      ]
    },
    "owner": {
      "blog": "https://shipeasy.ai",
      "name": "shipeasy.ai",
      "type": "Organization",
      "login": "shipeasy-ai",
      "company": null,
      "location": "United States of America",
      "followers": 1,
      "avatar_url": "https://avatars.githubusercontent.com/u/279595979?v=4",
      "created_at": "2026-04-27T03:38:02Z",
      "is_verified": null,
      "public_repos": 9,
      "account_age_days": 87
    },
    "license": {
      "state": "absent",
      "spdx_id": null,
      "raw_spdx": null,
      "file_present": false,
      "scorecard_found": false,
      "profile_has_license": false
    },
    "activity": {
      "releases": [],
      "recent_commits": [
        {
          "oid": "0a8071c4432ee583c42927e9cc2371267848d7f1",
          "body": "Promote OpsRun/OpsInvestigation `completedAction` from an inline\n`link_pr|notify|status|superseded` string union to a named `OpsRunAction`\nschema (+ `OpsRunActionOrNull`), mirroring `OpsItemStatus`. Codegen now emits\na real TS enum in every generated client, so consumers reference members\n(`OpsRunAction.LINK_PR`) instead of raw strings.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(ops): name the run-action enum in the contract (OpsRunAction)",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-22T23:54:34Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "0fb19934a3cdbcddff1d4f7076813c2db7973e22",
          "body": "CreateConfigRequest + UpdateConfigRequest gain optional dev/staging/prod\nobject props. On the CLI/MCP surface they project to --dev/--staging/--prod\n<json> flags (e.g. `release configs update cfg --prod '{\"n\":2}'`), each\npublishing that value to the named env immediately, overriding the flat\n`value` for it. Regenerated openapi client + CLI/MCP surfaces.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(configs): per-env publish keys on create/update",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-22T23:08:52Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "51b458177823dbc6733bacdbf992b30120854589",
          "body": "Add operation-level x-cli.hidden; both generators skip it. Keeps the five\nconfig ops (draft, discard-draft, publish, versions, activity) in the API\nspec + reference but drops them from the CLI command tree and MCP tool\nsurface. Regenerated commands.gen/tools.gen; updated tool-catalog + command-\ntree snapshots.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(configs): hide draft/publish/versions/activity ops from CLI+MCP",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-22T22:55:47Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "4ce7f8f02af5c8da815a6ded365bf6f79d59f15a",
          "body": "… stringify them\n\nThe `value` property on CreateConfig/UpdateConfig/SaveConfigDraft was declared\nwith no `type`, so the generated MCP inputSchema left it freeform. The Claude\nCode harness (and other MCP hosts) serialise an object argument to a JSON\nstring when the schema doesn't pin it to `type: \"ob\n[…]\ns accurate for both the flat and\nthe `{env: value}` forms. Regenerated the bundle, typed client, zod, MCP tools,\nand CLI commands.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(openapi): type config `value` params as object so MCP hosts don't…",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-22T22:41:33Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "4e241439cabc79167822d439d5e6837b655fc941",
          "body": "Add a MetricDisplayUnit schema (nullable string — e.g. ms, %, $) and thread a\n`unit` field through the create/update metric request variants\n(CreateMetricWithQuery[/Ir], UpdateMetricWithQuery[/Ir], UpdateMetricFields).\nRegenerate the openapi bundle, TS/zod types, and the MCP tools from the spec.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(metrics): add optional display unit to metric definitions",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-22T21:09:05Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "1cef9cd8884306637bd15524fc8e9223f67df1fd",
          "body": "The queue-work loop now acks each item the moment it's picked up\n(`shipeasy ops ack`), which opens the run that lands finished work in the\nAction-required lane instead of No progress. Agent is auto-detected; no\ntrigger connector required (connector-less run). Replaces the manual\nin_progress status flip.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs(ops-work): ack items on pickup to record a run",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-22T19:12:20Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "e70d97ded69ff2114efb64c1684fb94867e56281",
          "body": "The metrics_grammar reference listed ratios under NOT SUPPORTED, but the\nruntime parser/IR (packages/query-dsl) has supported the binary ratio(arm,\narm) form end-to-end for a while. Document it: BNF, a RATIO section, the\ncohort-rate-not-id-join semantics, and two examples; narrow NOT SUPPORTED to\nge\n[…]\neral arithmetic. Also fix the stale source-of-truth pointer (the vendored\ncli/src/query-dsl copy lags and is off the create path).\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs(metrics): document the ratio() DSL form in the grammar",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-22T17:11:33Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "fd037f1f691f4a10966348f5731ccb79e7819da8",
          "body": "…itle)\n\nMCP clients (Claude, etc.) bucket tools by the per-tool `annotations`\nobject in tools/list — readOnlyHint / destructiveHint / idempotentHint /\ntitle. We emitted none, so every tool fell into \"other tools\".\n\nDerive them in gen-tools.mjs from the HTTP method + x-cli verb: GET\n(list/get) = read\n[…]\n).\n\nReaches both the stdio server and the hosted mcp-worker unchanged — both\npass the tool objects straight through to tools/list.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(mcp): emit tool annotations (readOnly/destructive/idempotent + t…",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-22T15:53:45Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "e3e51f0d8e351cd040b9f500932d5b7c4f95b878",
          "body": "Expose the investigation surface as a proper Ops sub-resource and add an\nin-place update so a delegated agent can write its findings back into the\n`working` run record it was handed:\n\n- New `Investigations` tag (parent Ops) — createOpsInvestigation and\n  listOpsInvestigations were silently dropped f\n[…]\ner=, Copilot repo → /tasks/). Never an input.\n\nRegenerated the typed client, CLI commands + snapshot + docs, and MCP tools +\ndocs.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(ops): investigation write-back API + derived run session URL",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-22T02:33:46Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "9409c6a441d7a790ded5434e14b015929eaaaf36",
          "body": "admin/ops keys are env-agnostic (server pins them to prod) but the create\nendpoint still requires an env field, so default it to prod and always send.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(cli): always send env on key create (endpoint requires it)",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-21T19:47:42Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "af02dd23459bd6a8cd0b703c26579a7ac6c26c2c",
          "body": "…tags\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore(mcp): regenerate tools for ops create owner/status/subscribers/…",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-21T19:47:40Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "65695b64fd49435b3eb1afbaa6d4d982f9f6fc30",
          "body": "…uest\n\nExtend CreateBugRequest + CreateFeatureRequestRequest with optional\nstatus, assigneeId, subscribers[], and tags[] so a bug / feature request\ncan carry its owner, initial status, Slack subscribers, and tags in the\nsingle POST /api/admin/ops call. Regenerated openapi.{yaml,json} + the\ntyped client/zod validators.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(openapi): accept owner/status/subscribers/tags on ops create req…",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-21T17:05:37Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "1bba46a2619066f04ddf868fa573dad35437d2e2",
          "body": "Mirror of @shipeasy/core's buildCopilotAgentFile: the generated\n.github/agents/shipeasy.agent.md now wires the shipeasy MCP server as a remote\n`type: http` endpoint (project-scoped /p/<id>/mcp) authenticated by a\n`Authorization: Bearer ${{ secrets.COPILOT_MCP_SHIPEASY_CLI_TOKEN }}` header\n(a semcp_ \n[…]\ntead of the local `npx @shipeasy/mcp` stdio server.\nNo npm cold-start in the coding-agent sandbox. mcpBaseUrl overridable for e2e.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(cli): Copilot agent file targets remote MCP over Bearer",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-21T03:15:21Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "f49e31329c6d19255e7e9f49dbbce8e03c761594",
          "body": "The gate create/update MCP tool input-schemas embed the request-body JSON\nschema; regenerate so they carry the new `whitelist` condition property.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore(mcp): regenerate tools.gen for gatekeeper `whitelist` field",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-19T16:50:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "ed7ff86d851d447eb7fcea31dda315061e82faa3",
          "body": "…on entries\n\nThe gate editor pins an allowlist condition and persists a `whitelist: true`\nmarker on it (round-tripped by every read view — read-gate-view, gate-flow,\nthe stack hovercard — and the editor itself). The condition sub-gate schema\ndeclares `additionalProperties: false` but never listed `w\n[…]\nen\nregenerate. It's a presentational sibling of `locked` — ignored by\nevaluation, which treats the entry as an ordinary condition.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(openapi): allow `whitelist` cosmetic marker on gatekeeper conditi…",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-19T16:49:19Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "1beeb9f82ac7dbe4148c8dfe61ef353afebce295",
          "body": "…hanges\n\nThe published @shipeasy/openapi@2.3.0 predates the ops-ack operations\n(ackOpsItem / listOpsAgents) and the errors-series / notifications-feed\nremovals, so publish-openapi idempotent-skipped and publish-cli's pre-publish\ntype-check resolved the stale 2.3.0 (missing ackOpsItem). Bumping the version\npublishes the current surface; cli's `^2.1.0` range then picks it up.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore(openapi): bump to 2.4.0 to publish the ops-ack surface + spec c…",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-18T06:05:56Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "c991d2bcdd502f1eb58419cd6a5bcedd8b742456",
          "body": "`GET/POST /api/admin/notifications/feed` (the dashboard bell's in-app feed +\nmark-read) is dashboard/mobile-private UI plumbing, read through server\nactions — not a CLI/MCP operation. Removes it from the spec (drops it from\nthe contract fuzz + generated clients; it had no MCP tool). The ops-attentio\n[…]\nT /api/admin/notifications` (createNotification) stays\ncontract-bound. The handlers move to handlers/internal/ in the parent repo.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(spec): move the notifications feed out of the public contract",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-18T05:08:11Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "888dca03b173949a627d066400cb8667881ba2e6",
          "body": "`POST /api/admin/errors/series` (getProjectErrorSeries) is a dashboard\nproxy to the Cloudflare Analytics Engine SQL API — it needs the UI\nworker's CF_API_TOKEN secret, which CI has no way to provision, so it can\nonly ever 503 under the contract fuzz. It's a dashboard-only chart feed,\nnot a CLI/MCP o\n[…]\n` stays contract-bound (excluded from\nthe fuzz as a sub-action route). The handler moves to handlers/internal/\nin the parent repo.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(spec): move project-wide error series out of the public contract",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-18T04:48:01Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "4ede981a82e98ff6c8541358719477e6353b6183",
          "body": "…as code\n\nA group/tool description authored with a hard-wrapped inline code span\n(`ops ack <handle> --agent\\n<type>`) emitted a `...` span containing a\nnewline. MDX can't parse a single-backtick span across a line break, so it\nread the `<handle>`/`<type>` inside as JSX and the docs build failed with\n[…]\n tag for <handle>\". escapeProse() now collapses internal\nwhitespace within each inline code segment; regenerated mcp-reference.md.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(mcp-docs): keep inline code spans single-line so MDX parses them …",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-18T04:09:56Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "f6891b95ce244562eb1e6739bb4db87c5cd36dcf",
          "body": "The skills-contract sdk-compile test bakes SDK snippets from the live\npublished docs and type-checks them against the installed SDK. The docs\nnow use addExtras/clearExtras/runWithExtras (shipped in 7.7.0), so the\nfrozen-lockfile install in ci.yml must resolve 7.7.0 or the snippets fail\nto compile. (skills-contract.yml already forces @latest; this keeps the\nroot `pnpm test` green too.)\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore(deps): bump @shipeasy/sdk 7.6.0 → 7.7.0 for the extras API",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-18T01:56:14Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "d50f14b6e09f205a13313ea12593b3fc38fea582",
          "body": "openapi-ts writes openapi-ts-error-*.log dumps on a failed/interrupted\ngen run; they're throwaway diagnostics, not artifacts to track.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore(openapi): ignore transient openapi-ts codegen error logs",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-18T01:56:13Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "a32a575d2be547d9740af0992562667227a42501",
          "body": "Default the acking agent (and session id, when the harness exposes one)\nfor `shipeasy ops ack` / the `ops_ack` MCP tool from the coding-agent\nharness driving the shell — the CLI reads harness env markers, the MCP\nserver reads the client's initialize handshake name with env as fallback.\nAn agent acks\n[…]\nags; a human at a plain terminal stays a\nhuman ack. `SHIPEASY_ACK_AGENT=<type>` forces a type, `=none|human|0`\nforces a human ack.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(cli,mcp): ops ack env-identification layer",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-18T01:55:36Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "b7f0f01d024a7dd74d78eb699e398f8d6b7a592d",
          "body": "…se-contract migration\n\nReconcile the hand-authored spec with what the admin handlers actually\nreturn, so every apps/ui handler can annotate its return with a generated\n*Response type (handlers/response-contract):\n\n- Rows gain the dashboard-consumed fields: gates (creatorEmail/updaterEmail/\n  versio\n[…]\n surface\nfor all new operations is deliberately NOT wired yet (registry pass\npending; cli/ and mcp/ changes stay uncommitted with that session).\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(spec): document the dashboard's full wire surface for the respon…",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-17T23:57:24Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "2044d371936128712d89b337a9c6fd1c7f37a07b",
          "body": "…d URL + release 2.7.0\n\nThe MCP step of `shipeasy upgrade` now resolves the project pin before\nforce-rewriting each agent's entry — the .shipeasy binding wins, else the\npin already in the config (X-Project-Id header or an already-scoped\n/p/<id>/mcp URL) is carried forward via the new existingMcpProj\n[…]\nh also pre-selects\nthe project at OAuth consent).\n\nBump to 2.7.0 so the release carries the scoped-URL setup wiring and this\nmigration together.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(cli): shipeasy upgrade migrates MCP entries to the project-scope…",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-17T03:54:39Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "61064fff68d5c9241d182c0feec2c1711e9cfac9",
          "body": "When a bound project is known, the written MCP config now points at\nhttps://mcp.shipeasy.ai/p/<projectId>/mcp instead of the bare /mcp. The\npath pins every tool call to that project (X-Project-Id header kept as the\nexplicit override) and — since OAuth clients echo the configured URL as the\nRFC 8707 \n[…]\nnsent screen pre-selects that\nexact project. Also gives Codex a real project pin: its config carries no\nheaders, so the URL is the only channel.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(cli): project-scoped MCP server URL (/p/<id>/mcp) in setup wiring",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-17T03:40:15Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "726c1bda1eb073cbfd892c9e1bafb73f3e60afe9",
          "body": "The killswitch-propagation leg flipped a switch, polled /sdk/evaluate for 24s,\nthen restored. It failed intermittently (\"flip … did NOT propagate, edge still\n<orig>\") — not a prod bug. Verified against prod: the admin write path is\nintact (D1 config_values v46=false→v47=true, and the KV `{pid}:prod:\n[…]\n 96s (> KV's ~60s SLA, with margin) before restoring, polling\nevery 3s; factor the flip/restore polling into one `pollFor` helper.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(prod-probe): hold killswitch flip past KV's 60s edge-cache SLA",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-11T17:00:47Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "2264f4c1c2b82822e664f3258a5561e7bc7f5a19",
          "body": "…tract tests)\n\nThe Admin-API contract fuzz failed `response_schema_conformance` on both\n`GET /api/admin/experiments` and `GET /api/admin/experiments/{id}`: the app\nprojects every experiment through one `toExperimentApiRow` allow-list, but the\ntwo response schemas here had drifted apart and both unde\n[…]\nields are optional, so both the enriched list rows and the lean\nby-id detail validate. Regenerated the bundle + hey-api types/zod.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(openapi): experiment API row schema matches the served shape (con…",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-11T16:34:16Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "997645f63544f820c88c6a03549a4683e5cdacaf",
          "body": "…h CLI snapshot\n\nThe skills-contract sdk-compile test pins @shipeasy/sdk, but at ^6.2.0 it\nresolved a pre-`universe()` SDK while the shipeasy-experiments skill's baked\n`release/experiments` snippet (fetched from the latest published SDK docs)\ncalls `client.universe(...).assign()` — so the snippet fa\n[…]\no refresh the CLI command-surface snapshot for the new `ops comments`\ngroup (issue-comments feature) so `commands.test.ts` passes.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(ci): type-check skill snippets against @shipeasy/sdk 7.x + refres…",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-11T16:33:26Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "9853c2769f0b34c73423ec1bbe47bcc1c8396d52",
          "body": "…erprint docs\n\nErrorRecord gains an optional occurrences array (ErrorOccurrence — the\nminimal per-instance payload: message/stack/url/env/extras + sampleRate\n+ seenAt), returned only by GET /api/admin/errors/{id}, newest first,\ncapped at 100. Detail rows are sampled past 10/100/1000 occurrences\nwhil\n[…]\nn updated: the key is now the issue title (errorType +\nsubject + outcome), not the normalized message. Regenerates the typed\nclient + MCP tools.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(openapi): getError returns sampled occurrences; title-based fing…",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-10T15:42:21Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "d1645112116e6079b296b3893b678a09f026ade0",
          "body": "The poll broke as soon as all 20 exposure units were visible, but exposures\nand metric events flush through separate Pipelines sinks — a slower events\nroll left Σy=0 and false-failed the exact-stats assert (observed live:\nΣy=0 at assert time, all 19 metric rows visible minutes later). Hold the\npoll until the expected metric mass has landed as well.",
          "is_bot": false,
          "headline": "fix(prod-probe): lake-verdict poll must wait for the events sink too",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-10T14:58:53Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0479371d109265477d1c48fcc8d5de058c6f256b",
          "body": "…series\n\nValidates exposure logging end to end: seeds gate-check exposures (6 units,\n2 duplicate rows) alongside the lake-verdict experiment cohort, then runs the\nhourly exposure_recalc cron's exact first-exposure query shape (per-unit\nMIN(ts_ms) → UTC day index) scoped to the run prefixes and asser\n[…]\nic\ncumulative enrollment curve with consistent totals; soft-skips until the\ncrons have produced rows.\n\nVerified green against the live canary (6/6 gate units, 20/20 experiment\nunits, day 20644 exact).",
          "is_bot": false,
          "headline": "test(prod-probe): exposure-timeline leg — recalc inputs + cumulative …",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-10T14:58:36Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "cd3a0a4ff5218f300d4c38cfc4cb4328ea3686dc",
          "body": "openapi 2.3.0 ships the resolveError client op; mcp 2.4.0 ships the\nerrors_resolve tool and pins @shipeasy/openapi to ^2.3.0 so the publish\nworkflow waits for the new openapi on npm before shipping mcp.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore(release): @shipeasy/openapi 2.3.0, @shipeasy/mcp 2.4.0",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-09T20:46:01Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "c251e87dc76101b793cda8498b8220d45b585f78",
          "body": "…rs_resolve\n\nNew single-purpose close-out action: no body, flips one tracked error to\nresolved (PATCH /errors/{id} pinned to { status: \"resolved\" }). Safe by\nconstruction — a resolved error reopens on recurrence — so it's the one\nerror mutation projected to the MCP surface (errors_resolve). The gene\n[…]\ng stay unprojected, and\nthe CLI keeps skipping the Errors tag wholesale.\n\nRegen: bundled spec, typed client, MCP tools.gen + mcp-reference docs.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(openapi,mcp): expose POST /api/admin/errors/{id}/resolve as erro…",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-09T20:38:18Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "2d4f76e9b1a4e45d496e1563d469172656bcb182",
          "body": "…elope\n\nField-scoped validation messages (path → message) alongside the existing\n`error`/`code`/`detail`, so a client form can attach each message to its own\ninput instead of collapsing everything into one banner. Regenerated the client\ntypes + zod.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(openapi): add structured per-field `fields` map to the Error env…",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-09T18:11:53Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "f786161b36d768a3547c53a1d7843d0529dd981b",
          "body": "Add scale-level checks for the canonical resolution order against live\n/sdk/evaluate on the canary:\n\n- probeGroupSplitSRM: 30/70 fixture over ≤800 deterministic units.\n  Step 2 (fully-allocated fast path) → ~100% enrolled; step 6 (group\n  hash) → observed split matches 30/70 by df=1 chi-square (SRM \n[…]\new fixtures registered in THROWAWAY_FIXTURES (stopped after each\nrun, reclaimed at start; stays under the Pro=10 running-exp cap).\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "test(prod-probe): verify the 7-step resolution chain at scale",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-09T00:55:47Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "3151273858ddd06f22e7ff78729093103eccf82f",
          "body": "…lines → R2 SQL\n\nSeeds a deterministic exposure+metric cohort through /collect as the first\nleg, then (as the last leg, after the sink's 300s roll) runs the verdict\nsufficient-stats SQL from experiment-platform/25-pipelines.md against the\nR2 Data Catalog over HTTP and asserts EXACT per-group n/Σy/Σy\n[…]\nnt exposed units at y=0 and exclusion of pre-exposure and never-exposed\npoison metrics. Gated on secrets.SHIPEASY_CATALOG_TOKEN (absent → skip).\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(probe): event-lake verdict leg — exact sufficient stats via Pipe…",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-08T23:55:12Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "ca114cf88be2342297091f0229e5ff65a6e5b434",
          "body": "The config-inheritance leg now also guards the two /sdk/evaluate fields the\nuniverse-first SDKs depend on: the per-entry experiments[e].universe tag (so\nuniverse(name).assign() can find the pooled experiment) and the top-level\nuniverses[name].defaults map (so a not-enrolled universe(name).get(field) still\nresolves to the universe default).\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "test(prod-probe): assert universe-first edge fields in the config leg",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-08T14:39:42Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "71f1fa0baaef9cdfdc06b20180f743aaecc93730",
          "body": "…ures to fit the running cap\n\nThe first §B4-live run showed the rework legs green (config-merge, targeting,\nholdout, append) and mutual exclusion genuinely working — probe_mx_a/b already\nown the universe pool ([0,4000)/[4000,8000)). Two follow-ups so the MX leg\nasserts instead of soft-skipping:\n\n- R\n[…]\nted, and a\n  run-start reclaim stops any left over from a prior run. Peak concurrent\n  fixtures now ~7, comfortably under the cap.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(prod-probe): reuse the standing pooled MX pair + stop rework fixt…",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-08T12:16:02Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "30a7e1bd2340319e8529b6c9ccd7d79d7d64f6a3",
          "body": "…he races, MX pooled-check\n\nThree fixes from the 2026-07-08 run (the new rework legs themselves passed:\nconfig-merge, targeting gate, holdout gate + negative-shape, append-variant):\n\n- mSPRT τ: a weak λ (|λ|≈0.08, far below the significance scale) that stays\n  static across τ is thin-signal, not a w\n[…]\nRESH fixture names (probe_mx_pa/pb) so the pair is born pooled\n  post-§B4 — a reused pre-§B4 row would stay hashVersion 1 forever.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(prod-probe): green up the first live run — mSPRT weak-λ, blob-cac…",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-08T11:53:02Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "e0881e438a8c34db1d4517c6f9713c1c3e3e50e9",
          "body": "…l mutual exclusion\n\nNow that §B4 flips new experiments to pooled assignment, a 100%-allocation\nexperiment claims the WHOLE universe pool — two can't coexist in one\nuniverse. Gave each single-experiment leg (config / targeting / holdout /\nappend) its own universe so their 100% allocations fit, and r\n[…]\nr blob) before the hard assert, so it soft-skips instead of\nfalse-failing during the deploy transition, then lights up on its own.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "test(prod-probe): make the rework legs pooled-safe (§B4) + assert rea…",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-08T03:05:33Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "d28eb94763c72c4e9b0dddad72a979bcf1ea886a",
          "body": "Five new eval-time legs assert the features added in the rework, all\ndeterministic off a single /sdk/evaluate response (no /collect, no AE\nsampling — the bucketing is fixed per unit). They build reusable\nthrowaway fixtures, so they gate on SHIPEASY_PROBE_MUTATE:\n\n- probeExperimentConfig — assignment\n[…]\nafter the stats-knob legs; header env docstring updated. No\nworkflow.yml change — MUTATE/SERVER_KEY/CLIENT_KEY are already passed.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "test(prod-probe): cover the Universes→Experiments→Groups rework",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-08T02:51:09Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "93834e530b2a2578aea6b0e71fe672fca3180e0e",
          "body": "…m + defaultHoldout\n\n- experiments list response: holdoutGate + reservedHeadroom so the API/CLI/MCP\n  can read back what create/update set.\n- projects: defaultHoldout (bp) on update/settings — seeds new universes' holdout.\n\nRegenerated types/zod + CLI commands + MCP tools.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(contract): §C read-back + settings — holdoutGate/reservedHeadroo…",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-08T01:52:32Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "d708d933ffb575b7a1879cc456c7523827203623",
          "body": "- universes: param_schema ({name,type,default}[]), recommended_headroom (bp),\n  description on create/update/list.\n- experiments: holdout_gate, reserved_headroom (bp) on create/update; group\n  params documented as override-only (subset of the universe schema); weights\n  sum to 10000 − reserved_headr\n[…]\n\nRegenerated the openapi bundle + hey-api types/zod, and the CLI commands + MCP\ntools that project the registry onto each surface.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(contract): §D universe/experiment/group rework — new fields",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-08T01:41:32Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "cb0da729aa706152cdf68a94eec0e1bfbe76db9e",
          "body": "`shipeasy setup` (copilot) now writes `.github/agents/shipeasy.agent.md` — a\nGitHub custom agent whose `mcp-servers.shipeasy` is a local stdio server\n(`npx @shipeasy/mcp`, project id inlined + COPILOT_MCP_SHIPEASY_CLI_TOKEN secret)\nand whose body is the ops-work prompt. The CLI sets that one repo se\n[…]\nnv\nwhen there's no config file, so the coding-agent-spawned stdio server can\nauthenticate from the injected COPILOT_MCP_* secrets.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(triggers): Copilot custom-agent file + env-cred MCP fallback",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-07T04:26:49Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "aa56aa267a372737adf865b32dd1bd556eb0a6f6",
          "body": "Cursor-flavored plugin.json mirroring the .claude-plugin/.codex-plugin/.plugin\nmanifests — bundles all 10 skills (./skills/) and the shipeasy MCP server\n(./.mcp.json, hosted HTTP endpoint that Cursor reads under mcpServers).\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(marketplace): add Cursor plugin manifest",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-07T04:07:19Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "8aa8d1ff38cbaf65be52ee25f3c460af6852669c",
          "body": "The admin error envelope now echoes the expected JSON Schema back when a\nvalue fails schema validation (e.g. a config `value` that doesn't match its\nconfig's saved schema), so a caller can correct the value and retry without\nre-fetching. Makes the `schema` field first-class in the spec's `Error`\nschema (previously `additionalProperties: false` would have rejected it).\nRegenerates the bundle + SDK types/zod.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(openapi): add `schema` to the Error envelope",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-06T23:34:47Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "f35de6299d709ef6b1f3c3bb4162a98269ab0f9d",
          "body": "The MCP tool result only renders the thrown message, so the actionable\nguidance core carefully authors on its ApiErrors (`instructions`) never\nreached the calling agent. Fold `instructions` into the surfaced message\nin `unwrap` — e.g. a config value/schema mismatch now returns the expected\nJSON Schema to the agent so it can fix `value` and retry without a second\nround-trip. Adds unwrap unit coverage.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(mcp): surface ApiError `instructions` in the thrown tool error",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-06T23:25:29Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "a517e786e4f87b23a246081a4920e227e1868559",
          "body": "Some MCP hosts serialise a structured (object/array) tool argument to a\nJSON string when the tool's JSON Schema doesn't pin the property to\n`type: \"object\"`/`\"array\"` — the known marshalling bug. For freeform\nparams like a config draft `value` (no declared `type`), the admin API\nthen rejected the st\n[…]\narray literal. Scalars, enums, and\nnon-JSON strings pass through untouched, so a plain \"true\"/\"42\"/\"hello\"\nvalue is never coerced.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(mcp): revive over-stringified structured tool args before dispatch",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-06T23:16:27Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "3638834285c5efd703b2984cae08495ddc8242a9",
          "body": "…Servers\n\nSwitch the shared .mcp.json from the local `npx @shipeasy/mcp` subprocess\nto the hosted streamable-HTTP server (https://mcp.shipeasy.ai/mcp), mirroring\nthe CLI's canonical serverSpec() incl. the X-Shipeasy-List-Guard header. This\nflips both Claude and Codex (which share ./.mcp.json) to the\n[…]\n`keywords` fields to the Claude plugin.json\nso it matches the Codex and Copilot manifests instead of relying on implicit\ndefaults.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(plugin): claude plugin points at remote MCP + explicit skills/mcp…",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-06T21:20:19Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "43e039221f7357a3fdc6c93b19e304b9c7f833ac",
          "body": "…goal\n\n- OpsErrorContext gains `stackTail`: the last 3 frames of the latest\n  occurrence's stack, so the ops loop gets an at-a-glance throw locator\n  without a second `related.error` fetch. Documented in the errors runbook.\n- OpsMeasurePlanContext gains `goal`: the customer's intent in their own\n  w\n[…]\ne, and creates additional metrics/events the goal needs even off\n  spec.\n- Regenerated the bundled contract + generated types/zod.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(ops): richer AI ticket context — error stackTail + measure-plan …",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-06T17:23:33Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "cd44623ad44a88947222cf8387bb6ba0356b0c0b",
          "body": "Define comments on ops/feedback items in the OpenAPI spec so the whole surface\nis generated like everything else:\n\n- new Comments tag (child of Ops)\n- GET  /api/admin/ops/{handle}/comments  → listOpsComments (read the thread)\n- POST /api/admin/ops/{handle}/comments  → createOpsComment (append; markd\n[…]\nmments list|create`). The\ntools.gen.ts regen also reconciles the pending ciConfidence/allocation drift\nfrom the prior spec commit.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(ops): comment operations (list + create) on queue items",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-06T16:55:40Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "6184b30a76e3c29aac514fb4dd623634752a05b6",
          "body": "…ect defaults\n\nUpdateProjectRequest: ciConfidence becomes a free level in [0.5, 0.999]\n(was the 0.95/0.99 literal union) so the dashboard can offer an 'Other…'\ncustom confidence; add defaultAllocationPct (bp), defaultWinsorizePct, and\ndefaultMei — the per-project experiment defaults that seed new experiments\nand metrics. Mirrored on the Project response shape.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(openapi): widen ciConfidence + add allocation/winsorize/MEI proj…",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-06T04:16:59Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "cac1ca78d1c98f2be773aa03bd9a75b4f345b768",
          "body": "…n canary)\n\nRan the three stats legs end-to-end against the Eval Probe Canary and fixed\nwhat surfaced:\n\n- Throttle /collect (chunks of 20, 500ms gap). Analytics Engine samples per\n  index above ~100 data points/sec, so a 200-event burst lost most of its\n  events and signal; pacing recovers a usable \n[…]\nrified: exit 0 on the canary — λ null on fixed ✓, ci_confidence ✓, and CUPED\nvariance reduction fired (238→173) on a clean freeze.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(prod-probe): harden stats legs for live prod AE (verified green o…",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-06T04:13:50Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "ae561c1d95a89ef39ebc96482a64bc8e62e8824d",
          "body": "…s them\n\nThe stats legs create their fixtures with an inline goal metric, which registers\nthe backing event as pending:0 but does NOT rebuild the :catalog KV blob the edge\n/collect gate reads (only the events handlers call rebuildCatalog). So seeding a\ncohort 422'd \"Unregistered event names\" forever\n[…]\nt; always rebuilds the catalog), and retry the Unregistered\n422 in collect() to ride out the edge's per-isolate 60s catalog cache.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(prod-probe): approve inline-metric events so the edge catalog see…",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-06T03:20:42Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "b98c171cfc0b15a74a1ba10617378126cca795f5",
          "body": "…n knobs absent\n\n`projects current` (getCurrentProject) is not a real route — /api/admin/projects/current\ncollides with /projects/[id] (id=\"current\") and 403s — so probeStatsEffect and the\nthree stats-knob legs could never read the project. Read it by id through the\nwithAdmin GET /api/admin/projects\n[…]\nht up automatically once prod redeploys — so SHIPEASY_PROBE_MUTATE\ncan be enabled ahead of the deploy without reddening the probe.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(prod-probe): read project via admin GET, soft-skip stats legs whe…",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-06T02:50:46Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "416cffe36d625cf6613e878863c260a3cae245b5",
          "body": "The generated shipeasy-wiring.md told the agent to init the SDK and bind\na per-user client, but never to populate the identity/attributes bag — so\na straight follow-through left every evaluation seeing an empty context\n(only default rules + 100% rollouts fire, experiments can't bucket).\n\nAdd a per-t\n[…]\nargets feed\nthe same transform through identify(). Gate on the platform auto-inferring\nthe schema (release flags attributes list).\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(cli): instruct wiring doc to wire identity + targeting attributes",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-06T02:48:13Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "d866fdce5af70b45700c7a1bd50f767d721de98d",
          "body": "…s SKILL.md; sharpen see routing\n\nThe see code-instrumentation cases assert only that shipeasy-see fires and have\nno MCP surface (see() is a pure code primitive the sandbox can't let the agent\nwrite). Headless Haiku consults the skill by READING\n.claude/skills/shipeasy-see/SKILL.md rather than invok\n[…]\n), not console.error. Previously Haiku dove straight into\ngeneric error handling for that phrasing.\n\nshipeasy-see.json 4/4 at K=1.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(skills-eval,shipeasy-see): credit a skill consulted by reading it…",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-05T23:38:44Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "29b1654298e01aae51f8d0aa7980acedc23db6cb",
          "body": "…knobs\n\nExtend the scheduled prod eval probe past the two knobs probeStatsEffect\nalready exercises (default_power→realized_mde, srm_threshold→srm_detected)\nto the analysis knobs that can only be tested with purpose-built fixtures:\n\n- probeSequentialTau: a sequential fixture (+ a fixed sibling) prove\n[…]\nwaway fixtures under SHIPEASY_PROBE_STATS_UNIVERSE (default\nprobe_stats; needs a Pro+ plan — soft-skip when create is plan-gated).\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(prod-probe): cover mSPRT τ, CUPED gates, and verdict-gate stats …",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-05T23:29:01Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "41d31cee0b10e12e905cf5032403a7147b1ab86d",
          "body": "The guard only recognised tools ending in _create, so an agent could file a bug\nvia the ops_bug/ops_feature convenience verbs and skip the mandatory ops_list\ndedup entirely (observed in skills-eval: ops_bug called with no prior list).\nMap both to the 'ops' family so they require the ops_list token l\n[…]\ncription'; the proration/seat\nwording is already asserted in assert_args against the filed content.\n\nshipeasy-ops.json 3/3 at K=1.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(mcp): extend list-before-create guard to ops_bug/ops_feature",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-05T23:04:22Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "2184060702f8b8029d1e8026ddb30faa9ee028aa",
          "body": "…teral from fixture\n\nTwo i18n-eval fixes:\n- run.ts: an eval agent escaped the MCP-only lockdown via the Monitor tool\n  (runs arbitrary shell) and python/git-committed into the real repo. Disallow\n  Monitor + the Task*/Workflow/ScheduleWakeup exec-capable tools alongside Bash.\n- fixture-overlay/app/e\n[…]\nd i18n key; the agent must list-by-value + update via MCP.\n\nshipeasy-i18n.json 4/4 at K=1 (change-existing-copy now routes clean).\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(skills-eval): close Monitor exec backdoor; drop 'Welcome back' li…",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-05T22:52:37Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "9206aaeb456a4b43b5c36d753aa93b1f60a47617",
          "body": "Replace the round-trip check with an effect test: inject one deterministic,\nimbalanced synthetic cohort and reanalyze while varying a knob to a random\nin-range value, asserting the persisted result moves as the statistics require\n— default_power raises realized_mde monotonically, and a srm_threshold\n[…]\n sequential, CUPED\nneeds baselines, min_sample/min_runtime/ci seed or display) are left to the\nworker unit sims rather than faked.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "test(prod-probe): stats knobs must AFFECT analysis, not just save",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-05T22:37:56Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "ede38841b5a0301c06aafff391f23997518cf0e7",
          "body": "Add 10 analysis-pipeline knobs (min sample size/runtime, target power, CI\nlevel, CUPED window/overlap/min-users, mSPRT tau factors, SRM threshold) to\nUpdateProjectRequest + GetCurrentProjectResponse. They flow through the\ngenerated Zod, the CLI `projects update` options and the `projects_update`\nMCP tool. prod-probe round-trips every knob under SHIPEASY_PROBE_MUTATE.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(api): expose per-project statistics knobs on projects update",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-05T22:17:34Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "7c22ce1b5049ff848f5fbe96cacea4295e213f5b",
          "body": "…'get started' to setup\n\nOnboarding eval: bare \"set up metrics/alerting\" now confirms the platform is\nready and offers to create the first metric/alert (matching flags/experiments\nphrasing) instead of only interrogating; \"how do I get started with shipeasy in\nthis project\" now routes to shipeasy-setup even when the repo already looks\nShipeasy-shaped. onboarding.json 10/10 at K=1.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(skills): offer to create first metric/alert on bare setup; route …",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-05T22:13:26Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "72e89188220154938fe8d253df6d0f93d6c65fc8",
          "body": "BREAKING. Relocate the experiment \"minimum effect\" model to match the\nstatistics (see experiment-platform/06-analysis.md):\n\n- metric `min_detectable_effect` -> `default_min_effect_of_interest`\n  (a metric-level DEFAULT judgment, the effect *of interest* — renamed).\n- new per-attachment override `min\n[…]\nectable\n  effect given observed variance + n, a read-only output.\n\nRegenerates the openapi types/zod, CLI commands, and MCP tools.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(api)!: split minimum effect of interest from detectable effect",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-05T17:55:35Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "aa6dd60c719772deee72b6fb951478790c30e73c",
          "body": "Align the metrics tuning-knob guidance with the actual field name\n(default_min_effect_of_interest, per-experiment override\nmin_effect_of_interest, realized_mde in results) rather than the\nplaceholder minDetectableEffect.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(shipeasy-metrics): correct MDE knob to defaultMinEffectOfInterest",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-05T17:46:18Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "8c145a97e486577adfe8644c5b4ad18a5c546329",
          "body": "…s; deterministic exp fixtures\n\nSkill:\n- Distinguish variation POINT (one) from variant ARMS (several): when the user\n  didn't pin variants, propose a few candidate arms and let them select which to\n  include (multi-select) — control + N treatments, with the traffic-split\n  tradeoff.\n- New \"Statisti\n[…]\nchosen name\n  (which flaked start between green_checkout_button and checkout_button).\n\nexperiments eval 4/4 at K=1, deterministic.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(shipeasy-experiments): multi-arm variants + all statistical knob…",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-05T17:44:11Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "a1d50beee2c0481c2b95e85764d33e7ccb731b64",
          "body": "The list-before-create guard (a fresh *_list must precede each *_create)\nwas stdio-only, toggled by SHIPEASY_MCP_LIST_GUARD env. Make it work on\nthe hosted worker too, carried per-connection by an X-Shipeasy-List-Guard\nheader (env can't be per-connection on a Worker).\n\n- list-guard: setGuardSecret()\n[…]\n DISABLED (off, the hosted\n  default) plus a JSON-safe //list-guard note, so it's present, annotated,\n  and one edit away from on.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: list-before-create guard on the remote MCP + setup wiring",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-05T17:28:52Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "91c91bb76fc77dbd99084ad5a6d5926540a3eee0",
          "body": "- Make the list-before-propose scan (events + metrics + alerts) a hard gate:\n  don't propose the plan or create the rule until all three lists return. The\n  original run proposed with \"saw [none]\" — no scan at all.\n- Surface, don't silently default, the knobs the user left open — chiefly\n  windowHou\n[…]\n windowHours (the prompt gives no\n  period, so the skill must land one, not omit it).\n\nalerts eval 4/4 at K=1 (args now verified).\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(shipeasy-alerts): surface windowHours options + hard pre-scan gate",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-05T17:18:19Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "13bebb0f907ae9883d7fab073ef70050e4b84b60",
          "body": "Every catalogued ErrorCode must be declared on >=1 operation (the spec.test\n'unused ErrorCode' guard). Drop CONFLICT, EXPERIMENT_NOT_FOUND,\nFEATURE_REQUIRES_UPGRADE, INVALID_JSON (dead/redundant — see @shipeasy/core);\ndocument PLAN_LIMIT on the create/start ops that enforce plan quotas\n(checkLimit) \n[…]\n their real ops.\nRegenerate the bundle + client (also picks up the committed tickets:public_create\nscope, fixing cli keys-scopes).\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(openapi): reconcile ErrorCode catalogue with operations",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-05T17:14:26Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "b1a39c7b1d6ef668c0a57ce6c3b6c194553d34a9",
          "body": "… nudge\n\nRunner (skills-eval):\n- Multi-turn auto-approve: after a turn, an outcome-gated case (expect_state)\n  that only listed/proposed is resumed on the SAME session with an approval,\n  so the agent carries its recommended default through to the create — the\n  transport-level version of the standi\n[…]\nnow mandatory (an un-fired event\n  makes the metric read zero), stated in step 3 and Hard rules.\n\nmetrics eval: 1/4 -> 4/4 at K=1.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(skills-eval,mcp): auto-accept consultative pauses + event-wiring…",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-05T17:10:01Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "a82fa381a822ec6dcfae40b9276088275cf1234c",
          "body": "`shipeasy setup` and `shipeasy mcp install` now write the bound project\ninto each JSON MCP config (`headers: { \"X-Project-Id\": <uuid> }`), so a\nper-repo .mcp.json targets its own project without relying on the OAuth\nconsent-time pick. The header is not a credential — the remote MCP\nserver still auth\n[…]\ned-in project).\n- Codex HTTP MCP has no header flag, so it stays URL-only and notes that\n  the project is chosen at OAuth consent.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(cli): pin project via X-Project-Id header in setup MCP wiring",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-05T17:06:13Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "9d017afdbd5e917b0ab48f3070f74d6cf044cc3e",
          "body": "New this release: `shipeasy report-issue` (consent-gated setup-failure bug\nreporting to Shipeasy) with the production report key baked in; `sdk keys\ncreate --name/--scopes` (scopes validated against the spec enum); and the\nrequest helper now surfaces the admin API's field-level validation `detail`.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore(cli): release 2.6.0",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-05T16:40:29Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "331968b05a0fea064e912f7bbf1c2aab94049ff8",
          "body": "Sets BAKED_REPORT_KEY to Shipeasy's own public client key (minted on the main\nproject, scoped to tickets:public_create only) so `shipeasy report-issue` /\nsetup-failure reporting is live. Client keys are public-by-design — safe to\nembed — and this one can do nothing but file a rate-limited, pending_a\n[…]\nT_KEY` check would have gone false once the constant held the\nreal key). SHIPEASY_REPORT_KEY still overrides for testing/rotation.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(cli): bake in the production report client key",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-05T15:37:13Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "a9a9da3d959df2c1005c2f870aab7f34a26402f5",
          "body": "Recreate the app's /cli-auth/success look inline in the loopback page the\nCLI serves after browser auth: the on-brand animated beams backdrop,\ntranslucent card, purple check, \"finish automatically\" row + docs link,\nand a rotating \"Did you know?\" tip. Honours prefers-reduced-motion.\nReplaces the plain light/dark green-check card.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(cli): beams-background CLI auth loopback success/error page",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-05T15:35:50Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "8d513fc94c249177b93b0efac42ddd2f14e86f97",
          "body": "…T model\n\nDrive the behavioural skills-eval with the GitHub Copilot CLI as an\nalternative to claude -p, selected via a user argument (--copilot /\n--agent copilot / SHIPEASY_EVAL_AGENT). The copilot runner forces the\ncheapest GPT model (gpt-5-mini, overridable via SHIPEASY_EVAL_COPILOT_MODEL),\nmirror\n[…]\nia ask_user);\n  matchSkillToken maps a short plugin token (flags) to shipeasy-flags.\n- README + unit tests for the copilot parser.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(skills-eval): add copilot runner (--copilot), forces cheapest GP…",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-05T10:41:33Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "b3789ced3dea1b1015743fb9a24ad77bad4079d7",
          "body": "…amed)\n\nThe TS SDK repo was renamed shipeasy-ai/sdk → shipeasy-ai/sdk-ts to match the\nother SDK repos. Update the docs-fetcher repo map so `docs get/list/skill`\n(and the GitHub Pages base) resolve the renamed repo.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore(openapi): point typescript docs at shipeasy-ai/sdk-ts (repo ren…",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-05T04:37:20Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "982a5a6d1006aaa2194daf618368438e2dfa9a0e",
          "body": "…d snippets\n\nsdk-compile.test.ts asserted >5 extracted `ts` snippets importing @shipeasy/sdk,\nbut skills are language-neutral: their SDK call sites are {{SDK_SNIPPET:handle}}\nplaceholders baked at install time from the SDK's published docs. Until the SDK's\nGitHub Pages site is live, the bake degrade\n[…]\nting snippets are\nstill compiled by the it.each; baked ones flow in automatically once the docs\nsite publishes real `ts` snippets.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(skills-contract): guard on SDK_SNIPPET placeholders, not extracte…",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-05T04:37:20Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "5244dec18dc0d1e0727572a5ed221c996e7a9114",
          "body": "- hero.svg chip now shows `npm install -g @shipeasy/cli && shipeasy setup`\n  (was `claude plugin install shipeasy@shipeasy`); widened chip + smaller\n  mono font to fit.\n- add hero.gif screencast under the hero, optimized 14.6MB→5.3MB\n  (1440x900/401f → 900x563/12fps/96-color) to stay under GitHub's ~10MB\n  image-proxy cap so it renders/animates reliably.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs(readme): fix hero install command + add optimized hero.gif",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-05T04:34:08Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "56a85ce50efc0a5a7b7f791190223f5679c90b14",
          "body": "…te → propose → approve)\n\nReorient the create flows for the shipeasy-experiments, shipeasy-metrics,\nand shipeasy-alerts skills away from fire-and-forget auto-provisioning\ntoward a consultative loop: investigate the scoped surface the ask names\n(required), propose 2-4 variants, then STOP and wait for\n[…]\nthe eval system prompt so\na skill's own propose→provision step auto-approves in the eval, and\nrefresh the three create-case notes.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(skills): make experiments/metrics/alerts consultative (investiga…",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-05T04:19:11Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "5aebe35272b61820c7e59fd003ea5ce59f0c8eb7",
          "body": "A 422 from the admin API carries a `detail` string (e.g.\n`scopes.0: Invalid enum value…`) alongside the generic `error: \"Validation\nfailed\"`. The CLI request helper only read `error`, so every validation failure\ncollapsed to \"Validation failed\" with no clue what was wrong. Now the thrown\nApiError message includes `detail` when present.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(cli): surface the admin API's field-level validation detail",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-05T04:05:26Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "6a0a9e562c5f5e744f7174790765eb9067f33c28",
          "body": "…rize step\n\nThe list-guard signing secret was generated at module load via randomBytes(32).\nThe Cloudflare Workers runtime (mcp-worker imports @shipeasy/mcp/registry, which\npulls in list-guard) forbids generating random values in global scope, so the\nworker failed to boot with 'Disallowed operation \n[…]\n (MCP_AUTH_INSTRUCTIONS) and, under a coding-agent\nharness, a directive to authorize its own connection before running the wiring.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(mcp): lazy list-guard secret (workerd-safe) + CLI MCP OAuth autho…",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-05T03:56:24Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "c4d2a9d21c66ad0c0f3062fc0f2803d410fb8f47",
          "body": "…tHog/Confidence into Shipeasy\n\nOn-demand, intentionally-invoked workflow skill (not an auto-triggering area\nskill). Router SKILL.md + a shared references/conventions.md (target model,\ngate/config/experiment decision, the 16-op targeting vocabulary, plan/execute\nflow, resume) and one references/<pla\n[…]\ndence) skills don't have.\n\nRegisters the skill in EXPECTED_SKILLS and the three host plugin.json\ndescriptions + docs/reference.md.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(skills): add shipeasy-migrate — port Statsig/Eppo/Optimizely/Pos…",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-05T03:41:23Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "8deaf461ed79085a12268918969ae3970dde1807",
          "body": "Adds the two flags needed to mint a scoped, named client key (e.g. the CLI's own\n\"CLI main key\" for /cli/report). `--scopes` validates against the OpenAPI\nCreateKeyRequest scope enum read straight off the generated schema, so adding a\nscope to spec/components/schemas/keys.yaml extends the CLI automatically — no\nhardcoded list. Both flags flow into the CreateKeyRequest body (name + scopes\nwere already accepted by the API).\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(cli): --name and --scopes on `sdk keys create`",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-05T03:34:02Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "203038774a8c9a9bfcb4397227ae1304b6677750",
          "body": "Stage 3 of 3 — the CLI + agent surface for self-reported setup bugs:\n- `shipeasy report-issue` files a pending-approval bug to Shipeasy via the public\n  POST /cli/report endpoint, collecting OS/Node/CLI version, project id, language\n  and frameworks, plus the failing step + error. `--consent` is a H\n[…]\nelling out the ask-first, consent-required flow.\n- Adds the `tickets:public_create` scope to the OpenAPI key schema (spec source).\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(cli): consent-gated setup-failure bug reporting",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-05T03:14:48Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "113bc34097dd2407db4665faec9647592e9dba93",
          "body": "…opilot secrets\n\nThe setup command wired the hosted MCP server as the bare origin\n`https://mcp.shipeasy.ai`. The streamable-HTTP transport is served at\n`/mcp`; a bare-origin POST hits `/` and 404s (\"No handler for POST /\"),\nso every agent's MCP entry failed to initialize. Append the `/mcp` path.\n\nTh\n[…]\np, minting the ops key by reusing that token via a direct\nadmin-API call. No session -> the step degrades to a no-op, not a crash.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(cli): point MCP wiring at /mcp path and reuse session token for C…",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-05T00:53:44Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "fb706e0a9c7ff3ced7fc58d52cdef4c4247e10c8",
          "body": "Replace the Claude-plugin-install headline CTA with the one-command CLI\npath (`npm install -g @shipeasy/cli` → `shipeasy setup`); demote the\nper-host plugin/skills tiers into a collapsible details block.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs: lead README install with global CLI + shipeasy setup",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-05T00:48:13Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "4a62a8646a760fbf3d845717fc7caab9c18caf4a",
          "body": "…tice\n\nThe setup install multiselect let the user uncheck targets, but that only\ndeferred the install — de-selected folders still got a section in\nshipeasy-wiring.md, so the reading harness walked projects the user opted\nout of. Track de-selections and exclude them from the per-target loop, the\nbind\n[…]\nefore the shipeasy-mcp tools resolve.\nPer-agent reload commands for claude/cursor/copilot/codex/jules, generic\nfallback otherwise.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(cli): drop de-selected targets from wiring.md + add MCP reload no…",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-05T00:46:22Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "8894c17fc5fc48169b7c5a0a6f115802a9383e81",
          "body": "The admin API returns codes from @shipeasy/core's ErrorCode catalogue that\nthe spec enum never picked up (METRIC_NOT_FOUND, METRIC_UNKNOWN_ID, the\nEXPERIMENT_* family, CONFLICT, PLAN_LIMIT, FEATURE_REQUIRES_UPGRADE,\nINVALID_JSON). The contract fuzz caught POST /api/admin/alert-rules returning\n`code:\n[…]\n's\nx-error-codes. Regenerated bundle + SDK types.\n\nAlso folds in the plan-tier enum (free/pro/business/enterprise) example update.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(openapi): sync ErrorCode enum with @shipeasy/core catalogue",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-04T22:18:28Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "12e72fa87797e7f6097057ed8100c1b9bdccf156",
          "body": "When the user opts to launch a coding agent on shipeasy-wiring.md, pass that\nagent's skip-permission-prompts flag so it can read the checklist, edit entry\npoints, and write env unattended instead of stalling on an approval prompt for\nevery file op. Per-agent equivalent of Claude's --dangerously-skip\n[…]\n-dangerously-skip-permissions, codex →\n--dangerously-bypass-approvals-and-sandbox, cursor → --force, copilot →\n--allow-all-tools).\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(setup): auto-approve the launched wiring agent",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-04T22:10:18Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "a102f304e5e8be46e19e04bf7e1410ce49022c2d",
          "body": "…nstalls\n\n- Never add @shipeasy/react to JS/TS installs — it was sunset; the browser\n  build ships inside @shipeasy/sdk (the @shipeasy/sdk/client export). Covers\n  installArgv, sdkUpdateArgv, and the detect/scan install hints.\n- Map Claude to the `claude-code` skills-CLI name at project scope; bare\n\n[…]\nnvocation per\n  agent instead of one process per skill, listing each skill's description so\n  the customer can see what it is for.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(setup): drop nonexistent @shipeasy/react; batch + explain skill i…",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-04T22:06:44Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "f92b7e72bb224f7576f409ee6d0779eb7beeec33",
          "body": "pnpm forwards the bare `docs` subcommand to `npm docs`, which opens this\npackage's npmjs page (@shipeasy/repo) in a browser instead of running the\n`docs` script (`turbo run docs`). So every commit touching openapi/cli/mcp\npopped open https://www.npmjs.com/package/@shipeasy/repo. Add the missing\n`run` and a note, and fix the same `pnpm docs` footgun in the CLI/MCP READMEs.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(hooks): use `pnpm run docs`, not bare `pnpm docs`, in pre-commit",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-04T21:56:19Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "9e415194ecf0952a1aeda4debde4fed0429266ed",
          "body": "Ships the list-token guard (guarded *_create requires a fresh listToken from\nits *_list sibling) and its SHIPEASY_MCP_LIST_GUARD[_WINDOW_MINUTES] env knobs.\nPushing mcp/ to main triggers publish-mcp.yml (npm + MCP registry).\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore(mcp): release 2.3.0 — env-configurable list-before-create guard",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-04T21:36:54Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "9ea6baddac74f6569daf300fa16488092d025f62",
          "body": "Replace the all-or-nothing \"Run the SDK package install in N target(s)?\"\nconfirm with a multiselect (same picker as the agent selection). Each row\nshows the target path and which SDK + install command will run; unpicked\ntargets fall through to the existing deferred/wiring path.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(cli): let setup pick which targets get the SDK install",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-04T21:36:29Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "fe0bb8b671d05370d0690a37ce0bbac6d8fbc1db",
          "body": "Expose the guard through env vars, so it configures straight from an\nmcp.json / settings.json `env` block:\n\n  SHIPEASY_MCP_LIST_GUARD                on|off  (default on)\n  SHIPEASY_MCP_LIST_GUARD_WINDOW_MINUTES  number  (default 10)\n\nWhen off, `*_create` tools stop advertising `listToken` and the se\n[…]\ne and memoized (an MCP server's env is fixed for its lifetime),\nkeeping schema advertisement and runtime enforcement in lock-step.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(mcp): make the list-before-create guard configurable via env",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-04T21:34:43Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "727515315e16a0707b4ca6d608c9054f9b93eef6",
          "body": "Refuse a guarded `*_create` unless the caller echoes back the short-lived\n`listToken` its sibling `*_list` handed out — a forcing-function so the\nassistant checks for an existing resource before creating a duplicate.\n\n- Per-family: a create is guarded iff it ends in `_create` AND a\n  `${family}_list\n[…]\ness\n  as model guidance, not a security boundary. `listToken` never reaches the\n  wire (generated dispatch reads only named args).\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(mcp): guard *_create tools behind a fresh list-token",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-04T21:21:49Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "9ab2b19062dd9e9a2478837527a0716d89063259",
          "body": "ok() previously JSON.stringify'd the payload verbatim, so a successful call\nwith no content came back as a bare \"[]\", \"{}\", or — for a void mutation —\nJSON.stringify(undefined), i.e. a non-string `text`. Cheaper models read that\nempty payload as a failure and retry a call that already succeeded.\n\nEm\n[…]\nuilt-in\nreturning a tool_reference block, upstream of our MCP) — it fixes the analogous\nempty-result misread for the tools we own.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(mcp): give tool results an explicit \"success but empty\" envelope",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-04T21:08:31Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "fe9472916894a4e672cbc6d66b5e309e93bd472b",
          "body": "The ops_alerts_list dedup step checks for a rule already watching THIS\nmetric+threshold; the list will normally hold other unrelated rules, and\nthat must not block creating a genuinely new alert.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(skills): clarify alerts dedup — list isn't expected to be empty",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-04T20:50:19Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "de4ffe83c92e7596dbea892ca1e081a0477decf2",
          "body": "Address skills-eval routing misses under Haiku:\n\n- shipeasy-alerts: state plainly that Shipeasy IS the app's metrics + alerting\n  backend, so \"ping me if our error rate climbs above N%\" builds the\n  event->metric->rule chain here instead of being punted to Grafana/Sentry/Slack\n  or stalling on \"whic\n[…]\n change existing copy, find the backing key with\n  i18n_keys_list; don't grep the source for the string (it isn't a code literal).\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(skills): sharpen alerts/see/i18n routing for weak-model runs",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-04T20:37:10Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "2a7fc296f2a2e4087b3cdcd951b25e752f4ae0ee",
          "body": "Make the eval order-independent and self-contained:\n\n- setupState can now pre-seed alert rules (event -> metric -> alert), so\n  mutate-existing alert cases no longer depend on run order or on the\n  hardest create-case succeeding first. The seed metric is deliberately\n  domain-word-free so its name c\n[…]\new.\n- alerts/error-rate-threshold -> payment domain so the metric it creates can't\n  collide with the experiments checkout metric.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "test(skills-eval): seed alert rules + de-overlap metrics/alerts cases",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-04T20:36:57Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "914d18b2f93f8072b1667dd15fbb93e86fa87711",
          "body": "`shipeasy upgrade` brings a machine's Shipeasy install up to date in one\nverb: self-updates the CLI (npm/pnpm/yarn/bun), refreshes the coding-agent\nwiring (Claude plugin / MCP registration) and the marketplace how-to skills,\nand offers (never forces) an `@shipeasy/sdk` bump per onboarded target.\n\n`s\n[…]\ned flag to one level and the other's opts\ncome back empty (a --dry-run that silently runs for real). Covered by a\nregression test.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(cli): add `shipeasy upgrade` + `upgrade skills`",
          "author_name": "shipeasy-ai",
          "author_login": null,
          "committed_at": "2026-07-04T20:18:27Z",
          "body_truncated": true,
          "is_coding_agent": true
        }
      ],
      "releases_count": 0,
      "commits_last_year": 512,
      "latest_release_at": null,
      "latest_release_tag": null,
      "releases_from_tags": false,
      "days_since_last_push": 0,
      "active_weeks_last_year": 14,
      "days_since_latest_release": null,
      "mean_days_between_releases": null
    },
    "community": {
      "has_readme": true,
      "has_license": false,
      "has_description": true,
      "has_contributing": false,
      "health_percentage": 37,
      "has_issue_template": false,
      "has_code_of_conduct": false,
      "has_pull_request_template": false
    },
    "ecosystem": {
      "packages": [
        {
          "name": "@shipeasy/cli",
          "exists": true,
          "license": "MIT",
          "keywords": [],
          "ecosystem": "npm",
          "matches_repo": true,
          "registry_url": "https://www.npmjs.com/package/@shipeasy/cli",
          "is_deprecated": false,
          "latest_version": "2.7.0",
          "repository_url": "https://github.com/shipeasy-ai/shipeasy",
          "versions_count": 24,
          "total_downloads": null,
          "dependents_count": null,
          "deprecation_note": null,
          "maintainers_count": 1,
          "monthly_downloads": 2095,
          "first_published_at": "2026-05-12T20:03:29.133000Z",
          "latest_published_at": "2026-07-21T03:49:19.696000Z",
          "latest_version_yanked": null,
          "days_since_latest_publish": 2
        },
        {
          "name": "@shipeasy/mcp",
          "exists": true,
          "license": "MIT",
          "keywords": [
            "mcp",
            "model-context-protocol",
            "mcp-server",
            "feature-flags",
            "feature-gates",
            "feature-management",
            "feature-toggles",
            "ab-testing",
            "split-testing",
            "experimentation",
            "experiments",
            "kill-switch",
            "dynamic-config",
            "remote-config",
            "progressive-delivery",
            "feature-rollout",
            "canary-release",
            "i18n",
            "internationalization",
            "localization",
            "translations",
            "shipeasy",
            "claude",
            "claude-code",
            "cursor",
            "windsurf",
            "ai-agent",
            "llm-tools"
          ],
          "ecosystem": "npm",
          "matches_repo": true,
          "registry_url": "https://www.npmjs.com/package/@shipeasy/mcp",
          "is_deprecated": false,
          "latest_version": "2.4.0",
          "repository_url": "https://github.com/shipeasy-ai/shipeasy",
          "versions_count": 14,
          "total_downloads": null,
          "dependents_count": null,
          "deprecation_note": null,
          "maintainers_count": 1,
          "monthly_downloads": 2087,
          "first_published_at": "2026-05-12T20:03:22.874000Z",
          "latest_published_at": "2026-07-11T20:17:11.811000Z",
          "latest_version_yanked": null,
          "days_since_latest_publish": 11
        },
        {
          "name": "@shipeasy/openapi",
          "exists": true,
          "license": "MIT",
          "keywords": [],
          "ecosystem": "npm",
          "matches_repo": true,
          "registry_url": "https://www.npmjs.com/package/@shipeasy/openapi",
          "is_deprecated": false,
          "latest_version": "2.4.0",
          "repository_url": "https://github.com/shipeasy-ai/shipeasy",
          "versions_count": 10,
          "total_downloads": null,
          "dependents_count": null,
          "deprecation_note": null,
          "maintainers_count": 1,
          "monthly_downloads": 2077,
          "first_published_at": "2026-05-12T20:03:16.770000Z",
          "latest_published_at": "2026-07-18T07:21:47.788000Z",
          "latest_version_yanked": null,
          "days_since_latest_publish": 5
        }
      ]
    },
    "popularity": {
      "forks": 0,
      "stars": 0,
      "watchers": 0,
      "fork_history": {
        "days": [],
        "complete": true,
        "collected": 0,
        "total_forks": 0
      },
      "star_history": {
        "days": [],
        "complete": true,
        "collected": 0,
        "total_stars": 0,
        "collected_at": null
      },
      "open_issues_and_prs": 0
    },
    "ai_readiness": {
      "has_nix": false,
      "example_dirs": [],
      "has_llms_txt": false,
      "has_dockerfile": false,
      "has_mcp_signal": true,
      "bootstrap_files": [],
      "api_schema_files": [
        "openapi/openapi.json",
        "openapi/openapi.yaml",
        "openapi/spec/openapi.yaml"
      ],
      "has_devcontainer": false,
      "typecheck_configs": [
        "cli/tsconfig.json",
        "mcp/tsconfig.json",
        "openapi/tsconfig.json",
        "skills-contract/tsconfig.json",
        "skills-eval/tsconfig.json"
      ],
      "toolchain_manifests": [],
      "largest_source_bytes": 176624,
      "source_files_sampled": 156,
      "oversized_source_files": 2,
      "agent_instruction_files": [],
      "agent_instruction_max_bytes": null
    },
    "dependencies": {
      "manifests": [
        "cli/package.json",
        "mcp/package.json",
        "openapi/package.json",
        "package.json",
        "skills-contract/package.json",
        "skills-eval/package.json"
      ],
      "advisories": {
        "error": null,
        "scope": null,
        "source": null,
        "findings": [],
        "collected": false,
        "malicious": [],
        "truncated": false,
        "by_severity": {},
        "advisory_count": 0,
        "affected_count": 0,
        "assessed_count": 0,
        "malicious_count": 0,
        "assessed_package": null,
        "unassessed_count": 0,
        "direct_affected_count": 0
      },
      "ecosystems": [
        "npm"
      ],
      "dependencies": [
        {
          "name": "@babel/parser",
          "manifest": "cli/package.json",
          "ecosystem": "npm",
          "version_constraint": "^7.29.0"
        },
        {
          "name": "@babel/traverse",
          "manifest": "cli/package.json",
          "ecosystem": "npm",
          "version_constraint": "^7.29.0"
        },
        {
          "name": "@babel/types",
          "manifest": "cli/package.json",
          "ecosystem": "npm",
          "version_constraint": "^7.29.0"
        },
        {
          "name": "@shipeasy/openapi",
          "manifest": "cli/package.json",
          "ecosystem": "npm",
          "version_constraint": "workspace:^2.1.0"
        },
        {
          "name": "chalk",
          "manifest": "cli/package.json",
          "ecosystem": "npm",
          "version_constraint": "^5.3.0"
        },
        {
          "name": "cli-table3",
          "manifest": "cli/package.json",
          "ecosystem": "npm",
          "version_constraint": "^0.6.5"
        },
        {
          "name": "commander",
          "manifest": "cli/package.json",
          "ecosystem": "npm",
          "version_constraint": "^12.1.0"
        },
        {
          "name": "conf",
          "manifest": "cli/package.json",
          "ecosystem": "npm",
          "version_constraint": "^13.0.0"
        },
        {
          "name": "open",
          "manifest": "cli/package.json",
          "ecosystem": "npm",
          "version_constraint": "^10.1.0"
        },
        {
          "name": "ora",
          "manifest": "cli/package.json",
          "ecosystem": "npm",
          "version_constraint": "^8.1.0"
        },
        {
          "name": "package-manager-detector",
          "manifest": "cli/package.json",
          "ecosystem": "npm",
          "version_constraint": "^1.6.0"
        },
        {
          "name": "prompts",
          "manifest": "cli/package.json",
          "ecosystem": "npm",
          "version_constraint": "^2.4.2"
        },
        {
          "name": "typescript",
          "manifest": "cli/package.json",
          "ecosystem": "npm",
          "version_constraint": "^5.7.4"
        },
        {
          "name": "zod",
          "manifest": "cli/package.json",
          "ecosystem": "npm",
          "version_constraint": "^4.0.0"
        },
        {
          "name": "@modelcontextprotocol/sdk",
          "manifest": "mcp/package.json",
          "ecosystem": "npm",
          "version_constraint": "^1.29.0"
        },
        {
          "name": "@shipeasy/openapi",
          "manifest": "mcp/package.json",
          "ecosystem": "npm",
          "version_constraint": "workspace:^2.3.0"
        },
        {
          "name": "package-manager-detector",
          "manifest": "mcp/package.json",
          "ecosystem": "npm",
          "version_constraint": "^1.6.0"
        },
        {
          "name": "typescript",
          "manifest": "mcp/package.json",
          "ecosystem": "npm",
          "version_constraint": "^5.7.4"
        },
        {
          "name": "zod",
          "manifest": "mcp/package.json",
          "ecosystem": "npm",
          "version_constraint": "^4.0.0"
        },
        {
          "name": "zod",
          "manifest": "openapi/package.json",
          "ecosystem": "npm",
          "version_constraint": "^4.0.0"
        },
        {
          "name": "@shipeasy/cli",
          "manifest": "skills-contract/package.json",
          "ecosystem": "npm",
          "version_constraint": "workspace:*"
        },
        {
          "name": "@shipeasy/mcp",
          "manifest": "skills-contract/package.json",
          "ecosystem": "npm",
          "version_constraint": "workspace:*"
        },
        {
          "name": "@shipeasy/sdk",
          "manifest": "skills-contract/package.json",
          "ecosystem": "npm",
          "version_constraint": "^7.7.0"
        }
      ],
      "all_dependencies": {
        "error": "GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository",
        "source": null,
        "packages": [],
        "collected": false,
        "truncated": false,
        "total_count": null,
        "direct_count": null,
        "indirect_count": null
      }
    },
    "maintainership": {
      "issues": {
        "open_prs": 0,
        "merged_prs": 0,
        "open_issues": 0,
        "closed_ratio": null,
        "closed_issues": 0,
        "closed_unmerged_prs": 0
      },
      "bus_factor": null,
      "bot_contributors": 0,
      "top_contributors": [],
      "contributors_sampled": null,
      "top_contributor_share": null
    },
    "quality_signals": {
      "has_ci": true,
      "has_tests": true,
      "ci_workflows": [
        "ci.yml",
        "contract-tests.yml",
        "install-claude.yml",
        "install-codex.yml",
        "install-copilot.yml",
        "install-skills-matrix.yml",
        "prod-probe.yml",
        "publish-cli.yml",
        "publish-mcp.yml",
        "publish-openapi.yml",
        "skills-contract.yml"
      ],
      "has_docs_dir": true,
      "linter_configs": [],
      "has_editorconfig": false,
      "has_linter_config": false,
      "has_precommit_config": false
    },
    "security_signals": {
      "lockfiles": [
        "pnpm-lock.yaml"
      ],
      "scorecard": {
        "checks": [
          {
            "name": "Binary-Artifacts",
            "score": 10,
            "reason": "no binaries found in the repo",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#binary-artifacts"
          },
          {
            "name": "Branch-Protection",
            "score": 0,
            "reason": "branch protection not enabled on development/release branches",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#branch-protection"
          },
          {
            "name": "CI-Tests",
            "score": null,
            "reason": "no pull request found",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#ci-tests"
          },
          {
            "name": "CII-Best-Practices",
            "score": 0,
            "reason": "no effort to earn an OpenSSF best practices badge detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#cii-best-practices"
          },
          {
            "name": "Code-Review",
            "score": 0,
            "reason": "Found 0/30 approved changesets -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#code-review"
          },
          {
            "name": "Contributors",
            "score": 0,
            "reason": "project has 0 contributing companies or organizations -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#contributors"
          },
          {
            "name": "Dangerous-Workflow",
            "score": 10,
            "reason": "no dangerous workflow patterns detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dangerous-workflow"
          },
          {
            "name": "Dependency-Update-Tool",
            "score": 0,
            "reason": "no update tool detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dependency-update-tool"
          },
          {
            "name": "Fuzzing",
            "score": 0,
            "reason": "project is not fuzzed",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#fuzzing"
          },
          {
            "name": "License",
            "score": 0,
            "reason": "license file not detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#license"
          },
          {
            "name": "Maintained",
            "score": 0,
            "reason": "project was created within the last 90 days. Please review its contents carefully",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#maintained"
          },
          {
            "name": "Packaging",
            "score": 10,
            "reason": "packaging workflow detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#packaging"
          },
          {
            "name": "Pinned-Dependencies",
            "score": 0,
            "reason": "dependency not pinned by hash detected -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#pinned-dependencies"
          },
          {
            "name": "SAST",
            "score": 0,
            "reason": "no SAST tool detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#sast"
          },
          {
            "name": "Security-Policy",
            "score": 0,
            "reason": "security policy file not detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#security-policy"
          },
          {
            "name": "Signed-Releases",
            "score": null,
            "reason": "no releases found",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#signed-releases"
          },
          {
            "name": "Token-Permissions",
            "score": 0,
            "reason": "detected GitHub workflow tokens with excessive permissions",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#token-permissions"
          },
          {
            "name": "Vulnerabilities",
            "score": 0,
            "reason": "10 existing vulnerabilities detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#vulnerabilities"
          }
        ],
        "commit": "0a8071c4432ee583c42927e9cc2371267848d7f1",
        "ran_at": "2026-07-23T15:01:00Z",
        "aggregate_score": 2.4,
        "scorecard_version": "v5.5.0"
      },
      "has_codeql_workflow": false,
      "has_security_policy": false,
      "has_dependabot_config": false
    },
    "contribution_flow": {
      "collected": true,
      "ci_last_run_at": "2026-07-23T09:21:41Z",
      "oldest_open_prs": [],
      "last_merged_pr_at": null,
      "ci_last_conclusion": "SUCCESS",
      "oldest_open_issues": []
    }
  },
  "config": {
    "disabled_metrics": [],
    "disabled_categories": [],
    "disabled_components": {}
  },
  "source": {
    "url": "https://github.com/shipeasy-ai/shipeasy",
    "host": "github.com",
    "name": "shipeasy",
    "owner": "shipeasy-ai"
  },
  "metrics": {
    "overall": {
      "key": "overall",
      "band": "at_risk",
      "name": "Overall health",
      "note": null,
      "notes": [],
      "value": 40,
      "inputs": {
        "security": 24,
        "vitality": 39,
        "community": 25,
        "governance": 43,
        "engineering": 66
      },
      "components": []
    },
    "categories": [
      {
        "key": "vitality",
        "band": "at_risk",
        "name": "Vitality",
        "value": 39,
        "weight": 0.22,
        "metrics": [
          {
            "key": "development_activity",
            "band": "moderate",
            "name": "Development activity",
            "note": null,
            "notes": [],
            "value": 64,
            "inputs": {
              "commits_last_year": 512,
              "human_commit_share": 1,
              "days_since_last_push": 0,
              "active_weeks_last_year": 14
            },
            "components": [
              {
                "key": "push_recency",
                "name": "Push recency",
                "detail": "last push 0 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "push_recency",
                    "params": {
                      "days": 0
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_cadence",
                "name": "Commit cadence",
                "detail": "14/52 weeks with commits",
                "points": 9.7,
                "status": "partial",
                "details": [
                  {
                    "code": "commit_cadence_weeks",
                    "params": {
                      "weeks": 14
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_volume",
                "name": "Commit volume",
                "detail": "512 commits in the last year",
                "points": 18,
                "status": "met",
                "details": [
                  {
                    "code": "commits_last_year",
                    "params": {
                      "count": 512
                    }
                  }
                ],
                "max_points": 18
              },
              {
                "key": "openssf_scorecard_maintained",
                "name": "OpenSSF Scorecard: Maintained",
                "detail": "project was created within the last 90 days. Please review its contents carefully",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "release_discipline",
            "band": "critical",
            "name": "Release discipline",
            "note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: Signed-Releases. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "openssf_scorecard_signed_releases"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 1,
            "inputs": {
              "releases_count": 0
            },
            "components": [
              {
                "key": "ships_releases",
                "name": "Ships releases",
                "detail": "no releases published",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_releases_published",
                    "params": {}
                  }
                ],
                "max_points": 27
              },
              {
                "key": "release_recency",
                "name": "Release recency",
                "detail": "no releases",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_releases",
                    "params": {}
                  }
                ],
                "max_points": 36
              },
              {
                "key": "release_cadence",
                "name": "Release cadence",
                "detail": "no releases",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_releases",
                    "params": {}
                  }
                ],
                "max_points": 27
              },
              {
                "key": "openssf_scorecard_signed_releases",
                "name": "OpenSSF Scorecard: Signed-Releases",
                "detail": "no releases found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 10
              }
            ]
          },
          {
            "key": "abandonment",
            "band": "excellent",
            "name": "Abandonment",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "cap": null,
              "state": "unverified",
              "guards": [],
              "signals": [],
              "red_flag": false,
              "multiplier_pct": 100,
              "declared_reason": null,
              "unverified_reason": "repository_too_young",
              "unanswered_open_prs": null,
              "unanswered_open_issues": null,
              "days_since_last_merged_pr": null,
              "days_since_last_human_commit": null,
              "days_since_last_human_commit_is_floor": false
            },
            "components": [
              {
                "key": "project_is_still_maintained",
                "name": "Project is still maintained",
                "detail": "maintenance record not established from the collected data",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "abandonment_unverified",
                    "params": {}
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "description": "Is the project alive — is code being written and are releases shipping?"
      },
      {
        "key": "community",
        "band": "critical",
        "name": "Community & Adoption",
        "value": 25,
        "weight": 0.18,
        "metrics": [
          {
            "key": "popularity",
            "band": "critical",
            "name": "Popularity & adoption",
            "note": null,
            "notes": [],
            "value": 1,
            "inputs": {
              "forks": 0,
              "stars": 0,
              "watchers": 0,
              "growth_state": "unverified",
              "growth_factor_pct": 100,
              "growth_unverified_reason": "no_history"
            },
            "components": [
              {
                "key": "stars",
                "name": "Stars",
                "detail": "0 stars",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "stars",
                    "params": {
                      "count": 0
                    }
                  }
                ],
                "max_points": 60
              },
              {
                "key": "forks",
                "name": "Forks",
                "detail": "0 forks",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "forks",
                    "params": {
                      "count": 0
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "watchers",
                "name": "Watchers",
                "detail": "0 watchers",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "watchers",
                    "params": {
                      "count": 0
                    }
                  }
                ],
                "max_points": 15
              }
            ]
          },
          {
            "key": "community_health",
            "band": "critical",
            "name": "Community health",
            "note": null,
            "notes": [],
            "value": 25,
            "inputs": {
              "has_readme": true,
              "has_license": false,
              "has_contributing": false,
              "has_issue_template": false,
              "has_code_of_conduct": false,
              "has_pull_request_template": false
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 22.5,
                "status": "met",
                "details": [],
                "max_points": 22.5
              },
              {
                "key": "license",
                "name": "License",
                "detail": "no license file detected",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "license_absent",
                    "params": {}
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributing_guide",
                "name": "CONTRIBUTING guide",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 18
              },
              {
                "key": "code_of_conduct",
                "name": "Code of conduct",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 13.5
              },
              {
                "key": "issue_template",
                "name": "Issue template",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.2
              },
              {
                "key": "pr_template",
                "name": "PR template",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 6.3
              }
            ]
          },
          {
            "key": "ecosystem_adoption",
            "band": "moderate",
            "name": "Ecosystem adoption (downloads)",
            "note": "Excluded from scoring (no data or not applicable): Registry dependents. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "registry_dependents"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 63,
            "inputs": {
              "packages": [
                "@shipeasy/cli",
                "@shipeasy/mcp",
                "@shipeasy/openapi"
              ],
              "dependents": null,
              "ecosystems": "npm",
              "total_downloads": null,
              "monthly_downloads": 6259
            },
            "components": [
              {
                "key": "monthly_downloads",
                "name": "Monthly downloads",
                "detail": "6,259 downloads/month across npm",
                "points": 50.6,
                "status": "partial",
                "details": [
                  {
                    "code": "downloads_monthly",
                    "params": {
                      "count": 6259,
                      "ecosystems": "npm"
                    }
                  }
                ],
                "max_points": 80
              },
              {
                "key": "registry_dependents",
                "name": "Registry dependents",
                "detail": "not reported by this ecosystem",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "not_reported_by_this_ecosystem",
                    "params": {}
                  }
                ],
                "max_points": 20
              }
            ]
          }
        ],
        "description": "Does the project have users, downloads, attention, and a welcoming setup for contributors?"
      },
      {
        "key": "governance",
        "band": "at_risk",
        "name": "Sustainability & Governance",
        "value": 43,
        "weight": 0.24,
        "metrics": [
          {
            "key": "responsiveness",
            "band": "critical",
            "name": "Issue & PR responsiveness",
            "note": "Excluded from scoring (no data or not applicable): Issue resolution, PR acceptance. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "issue_resolution",
                    "pr_acceptance"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 1,
            "inputs": {
              "merged_prs": 0,
              "open_issues": 0,
              "closed_issues": 0,
              "issue_closed_ratio": null,
              "closed_unmerged_prs": 0
            },
            "components": [
              {
                "key": "issue_resolution",
                "name": "Issue resolution",
                "detail": "no issues or no data",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_issues_or_data",
                    "params": {}
                  }
                ],
                "max_points": 46.75
              },
              {
                "key": "pr_acceptance",
                "name": "PR acceptance",
                "detail": "no decided pull requests or no data",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_decided_prs_or_data",
                    "params": {}
                  }
                ],
                "max_points": 38.25
              },
              {
                "key": "openssf_scorecard_code_review",
                "name": "OpenSSF Scorecard: Code-Review",
                "detail": "Found 0/30 approved changesets -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              }
            ]
          },
          {
            "key": "stewardship",
            "band": "at_risk",
            "name": "Ownership & stewardship",
            "note": null,
            "notes": [],
            "value": 40,
            "inputs": {
              "followers": 1,
              "owner_type": "Organization",
              "is_verified": null,
              "owner_login": "shipeasy-ai",
              "public_repos": 9,
              "account_age_days": 87
            },
            "components": [
              {
                "key": "ownership_backing",
                "name": "Ownership backing",
                "detail": "organization-owned",
                "points": 30,
                "status": "met",
                "details": [
                  {
                    "code": "owner_organization",
                    "params": {}
                  }
                ],
                "max_points": 30
              },
              {
                "key": "verified_domain",
                "name": "Verified domain",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 20
              },
              {
                "key": "owner_reach",
                "name": "Owner reach",
                "detail": "1 followers of shipeasy-ai",
                "points": 2.2,
                "status": "partial",
                "details": [
                  {
                    "code": "owner_followers",
                    "params": {
                      "count": 1,
                      "login": "shipeasy-ai"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "track_record",
                "name": "Track record",
                "detail": "9 public repos, account ~0 yr old",
                "points": 7.8,
                "status": "partial",
                "details": [
                  {
                    "code": "public_repos",
                    "params": {
                      "count": 9
                    }
                  },
                  {
                    "code": "account_age_years",
                    "params": {
                      "years": 0
                    }
                  }
                ],
                "max_points": 25
              }
            ]
          },
          {
            "key": "package_maintenance",
            "band": "excellent",
            "name": "Package maintenance",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "packages": [
                "@shipeasy/cli",
                "@shipeasy/mcp",
                "@shipeasy/openapi"
              ],
              "ecosystems": "npm",
              "any_deprecated": false,
              "min_days_since_publish": 2
            },
            "components": [
              {
                "key": "published_resolvable",
                "name": "Published & resolvable",
                "detail": "3 package(s) on npm",
                "points": 25,
                "status": "met",
                "details": [
                  {
                    "code": "packages_published",
                    "params": {
                      "count": 3,
                      "ecosystems": "npm"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "publish_recency",
                "name": "Publish recency",
                "detail": "latest publish 2 days ago",
                "points": 35,
                "status": "met",
                "details": [
                  {
                    "code": "publish_recency",
                    "params": {
                      "days": 2
                    }
                  }
                ],
                "max_points": 35
              },
              {
                "key": "version_history",
                "name": "Version history",
                "detail": "24 published versions",
                "points": 20,
                "status": "met",
                "details": [
                  {
                    "code": "published_versions",
                    "params": {
                      "count": 24
                    }
                  }
                ],
                "max_points": 20
              },
              {
                "key": "not_deprecated",
                "name": "Not deprecated",
                "detail": "active, not deprecated or yanked",
                "points": 20,
                "status": "met",
                "details": [
                  {
                    "code": "package_not_deprecated",
                    "params": {}
                  }
                ],
                "max_points": 20
              }
            ]
          }
        ],
        "description": "Will the project survive its people — bus factor, responsiveness, who backs it, and package upkeep?"
      },
      {
        "key": "engineering",
        "band": "moderate",
        "name": "Engineering Quality",
        "value": 66,
        "weight": 0.2,
        "metrics": [
          {
            "key": "engineering_practices",
            "band": "moderate",
            "name": "Engineering practices",
            "note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: CI-Tests. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "openssf_scorecard_ci_tests"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 60,
            "inputs": {
              "has_ci": true,
              "has_tests": true,
              "has_editorconfig": false,
              "has_linter_config": false,
              "has_precommit_config": false
            },
            "components": [
              {
                "key": "ci_workflows",
                "name": "CI workflows",
                "detail": "11 workflow(s)",
                "points": 24,
                "status": "met",
                "details": [
                  {
                    "code": "ci_workflows",
                    "params": {
                      "count": 11
                    }
                  }
                ],
                "max_points": 24
              },
              {
                "key": "tests_present",
                "name": "Tests present",
                "detail": null,
                "points": 24,
                "status": "met",
                "details": [],
                "max_points": 24
              },
              {
                "key": "linter_config",
                "name": "Linter config",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 16
              },
              {
                "key": "pre_commit_hooks",
                "name": "Pre-commit hooks",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 9.6
              },
              {
                "key": "editorconfig",
                "name": ".editorconfig",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 6.4
              },
              {
                "key": "openssf_scorecard_ci_tests",
                "name": "OpenSSF Scorecard: CI-Tests",
                "detail": "no pull request found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 20
              }
            ]
          },
          {
            "key": "documentation",
            "band": "good",
            "name": "Documentation",
            "note": null,
            "notes": [],
            "value": 75,
            "inputs": {
              "topics": [],
              "has_wiki": true,
              "homepage": null,
              "has_readme": true,
              "has_docs_dir": true,
              "has_description": true
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 30,
                "status": "met",
                "details": [],
                "max_points": 30
              },
              {
                "key": "documentation_directory",
                "name": "Documentation directory",
                "detail": null,
                "points": 25,
                "status": "met",
                "details": [],
                "max_points": 25
              },
              {
                "key": "documentation_homepage_site",
                "name": "Documentation / homepage site",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              },
              {
                "key": "repository_description",
                "name": "Repository description",
                "detail": null,
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              },
              {
                "key": "topics",
                "name": "Topics",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              },
              {
                "key": "wiki",
                "name": "Wiki",
                "detail": null,
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          }
        ],
        "description": "Are baseline engineering and documentation practices in place?"
      },
      {
        "key": "security",
        "band": "critical",
        "name": "Security",
        "value": 24,
        "weight": 0.16,
        "metrics": [
          {
            "key": "security_posture",
            "band": "critical",
            "name": "Security posture",
            "note": "Excluded from scoring (no data or not applicable): CI-Tests, Signed-Releases. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "ci_tests",
                    "signed_releases"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 24,
            "inputs": {
              "source": "openssf_scorecard",
              "checks_evaluated": 16,
              "scorecard_version": "v5.5.0",
              "checks_inconclusive": 2,
              "scorecard_aggregate": 2.4
            },
            "components": [
              {
                "key": "binary_artifacts",
                "name": "Binary-Artifacts",
                "detail": "no binaries found in the repo",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "branch_protection",
                "name": "Branch-Protection",
                "detail": "branch protection not enabled on development/release branches",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "ci_tests",
                "name": "CI-Tests",
                "detail": "no pull request found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 2.5
              },
              {
                "key": "cii_best_practices",
                "name": "CII-Best-Practices",
                "detail": "no effort to earn an OpenSSF best practices badge detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "code_review",
                "name": "Code-Review",
                "detail": "Found 0/30 approved changesets -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "contributors",
                "name": "Contributors",
                "detail": "project has 0 contributing companies or organizations -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "dangerous_workflow",
                "name": "Dangerous-Workflow",
                "detail": "no dangerous workflow patterns detected",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              },
              {
                "key": "dependency_update_tool",
                "name": "Dependency-Update-Tool",
                "detail": "no update tool detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "fuzzing",
                "name": "Fuzzing",
                "detail": "project is not fuzzed",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "license",
                "name": "License",
                "detail": "license file not detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "maintained",
                "name": "Maintained",
                "detail": "project was created within the last 90 days. Please review its contents carefully",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "packaging",
                "name": "Packaging",
                "detail": "packaging workflow detected",
                "points": 5,
                "status": "met",
                "details": [],
                "max_points": 5
              },
              {
                "key": "pinned_dependencies",
                "name": "Pinned-Dependencies",
                "detail": "dependency not pinned by hash detected -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "sast",
                "name": "SAST",
                "detail": "no SAST tool detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "security_policy",
                "name": "Security-Policy",
                "detail": "security policy file not detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "signed_releases",
                "name": "Signed-Releases",
                "detail": "no releases found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 7.5
              },
              {
                "key": "token_permissions",
                "name": "Token-Permissions",
                "detail": "detected GitHub workflow tokens with excessive permissions",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "vulnerabilities",
                "name": "Vulnerabilities",
                "detail": "10 existing vulnerabilities detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              }
            ]
          },
          {
            "key": "high_risk_jurisdiction_exposure",
            "band": "excellent",
            "name": "High-Risk Jurisdiction Exposure",
            "note": "Only high-confidence self-published location evidence affects this multiplier. Ambiguous matches are review-only; country evidence is not proof of nationality, citizenship, legal registration, malicious intent, or sanctions status.",
            "notes": [
              {
                "code": "jurisdiction_evidence_limits",
                "params": {}
              }
            ],
            "value": 100,
            "inputs": {
              "meaning": "self-published location evidence; not nationality or citizenship",
              "red_flag": false,
              "exposures": [],
              "policy_countries": [
                "Russia",
                "Iran",
                "North Korea"
              ],
              "review_only_matches": 0,
              "assessed_self_published_locations": 1
            },
            "components": [
              {
                "key": "policy_exposure_multiplier",
                "name": "Policy exposure multiplier",
                "detail": "no confirmed policy-scope location match",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "jurisdiction_no_match",
                    "params": {}
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "description": "Are visible security and supply-chain practices strong, with no malicious dependency and no unresolved high-risk jurisdiction exposure?"
      },
      {
        "key": "ai_readiness",
        "band": "moderate",
        "name": "AI Readiness",
        "value": 57,
        "weight": 0,
        "metrics": [
          {
            "key": "ai_agent_context",
            "band": "at_risk",
            "name": "Agent context & guidance",
            "note": null,
            "notes": [],
            "value": 40,
            "inputs": {
              "has_llms_txt": false,
              "legible_history_share": 1,
              "agent_instruction_files": [],
              "agent_instruction_max_bytes": null
            },
            "components": [
              {
                "key": "agent_instructions",
                "name": "Agent instructions",
                "detail": "no CLAUDE.md / AGENTS.md / editor rules",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_agent_instructions",
                    "params": {}
                  }
                ],
                "max_points": 45
              },
              {
                "key": "machine_readable_docs_llms_txt",
                "name": "Machine-readable docs (llms.txt)",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              },
              {
                "key": "legible_commit_history",
                "name": "Legible commit history",
                "detail": "100 of 100 human commits state their intent (structured subject or explanatory body)",
                "points": 40,
                "status": "met",
                "details": [
                  {
                    "code": "legible_history",
                    "params": {
                      "legible": 100,
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 40
              }
            ]
          },
          {
            "key": "ai_verify_loop",
            "band": "moderate",
            "name": "Verify loop (build / test / typecheck)",
            "note": null,
            "notes": [],
            "value": 53,
            "inputs": {
              "has_nix": false,
              "has_tests": true,
              "lockfiles": [
                "pnpm-lock.yaml"
              ],
              "has_dockerfile": false,
              "typed_language": true,
              "bootstrap_files": [],
              "has_devcontainer": false,
              "has_linter_config": false,
              "typecheck_configs": [
                "cli/tsconfig.json",
                "mcp/tsconfig.json",
                "openapi/tsconfig.json",
                "skills-contract/tsconfig.json",
                "skills-eval/tsconfig.json"
              ],
              "agent_commit_share": 0.98,
              "toolchain_manifests": [],
              "dependency_bot_commit_share": 0
            },
            "components": [
              {
                "key": "one_command_bootstrap",
                "name": "One-command bootstrap",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 18
              },
              {
                "key": "automated_tests",
                "name": "Automated tests",
                "detail": null,
                "points": 22,
                "status": "met",
                "details": [],
                "max_points": 22
              },
              {
                "key": "lint_format_config",
                "name": "Lint / format config",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 11
              },
              {
                "key": "static_type_checking",
                "name": "Static type checking",
                "detail": "cli/tsconfig.json, mcp/tsconfig.json, openapi/tsconfig.json, skills-contract/tsconfig.json, skills-eval/tsconfig.json",
                "points": 11,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "cli/tsconfig.json, mcp/tsconfig.json, openapi/tsconfig.json, skills-contract/tsconfig.json, skills-eval/tsconfig.json"
                    }
                  }
                ],
                "max_points": 11
              },
              {
                "key": "reproducible_environment",
                "name": "Reproducible environment",
                "detail": "lockfile",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "lockfile"
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "demonstrated_agent_practice",
                "name": "Demonstrated agent practice",
                "detail": "98 of the last 100 commits agent-authored or agent-credited",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "agent_authored_commits",
                    "params": {
                      "count": 98,
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "automated_maintenance",
                "name": "Automated maintenance",
                "detail": "no automated dependency updates observed",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_dependency_automation",
                    "params": {}
                  }
                ],
                "max_points": 8
              },
              {
                "key": "openssf_scorecard_pinned_dependencies",
                "name": "OpenSSF Scorecard: Pinned-Dependencies",
                "detail": "dependency not pinned by hash detected -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "ai_code_legibility",
            "band": "excellent",
            "name": "Code legibility for models",
            "note": null,
            "notes": [],
            "value": 99,
            "inputs": {
              "primary_language": "TypeScript",
              "largest_source_bytes": 176624,
              "source_files_sampled": 156,
              "oversized_source_files": 2
            },
            "components": [
              {
                "key": "type_checkable_code",
                "name": "Type-checkable code",
                "detail": "TypeScript (statically typed)",
                "points": 45,
                "status": "met",
                "details": [
                  {
                    "code": "statically_typed_language",
                    "params": {
                      "language": "TypeScript"
                    }
                  }
                ],
                "max_points": 45
              },
              {
                "key": "manageable_file_sizes",
                "name": "Manageable file sizes",
                "detail": "2/156 source files over 60KB",
                "points": 54.3,
                "status": "partial",
                "details": [
                  {
                    "code": "oversized_source_files",
                    "params": {
                      "kb": 60,
                      "sampled": 156,
                      "oversized": 2
                    }
                  }
                ],
                "max_points": 55
              }
            ]
          },
          {
            "key": "ai_interfaces",
            "band": "moderate",
            "name": "Machine-readable interfaces",
            "note": null,
            "notes": [],
            "value": 60,
            "inputs": {
              "example_dirs": [],
              "has_mcp_signal": true,
              "api_schema_files": [
                "openapi/openapi.json",
                "openapi/openapi.yaml",
                "openapi/spec/openapi.yaml"
              ]
            },
            "components": [
              {
                "key": "api_schema_openapi_graphql_proto",
                "name": "API schema (OpenAPI/GraphQL/proto)",
                "detail": "openapi/openapi.json, openapi/openapi.yaml, openapi/spec/openapi.yaml",
                "points": 40,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "openapi/openapi.json, openapi/openapi.yaml, openapi/spec/openapi.yaml"
                    }
                  }
                ],
                "max_points": 40
              },
              {
                "key": "mcp_server",
                "name": "MCP server",
                "detail": null,
                "points": 20,
                "status": "met",
                "details": [],
                "max_points": 20
              },
              {
                "key": "runnable_examples",
                "name": "Runnable examples",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 40
              }
            ]
          }
        ],
        "description": "How well is the repo equipped to be developed and maintained with AI coding agents? An independent, experimental badge — weight 0.0, so it is surfaced on its own and does not affect the overall health score."
      }
    ],
    "metrics_version": "1.13.0"
  },
  "warnings": [
    "Contributor list unavailable",
    "GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository",
    "deps.dev does not index npm:@shipeasy/cli@2.7.0; advisories assessed against the repository dependency graph instead"
  ],
  "report_type": "repository",
  "generated_at": "2026-07-23T15:01:06.060606Z",
  "schema_version": "0.27.0",
  "badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/s/shipeasy-ai/shipeasy.svg",
  "full_name": "shipeasy-ai/shipeasy",
  "license_state": "absent",
  "license_spdx": null
}

Las puntuaciones son señales, no garantías. Reflejan prácticas públicamente visibles en GitHub; no son una auditoría de código ni una garantía de seguridad.

Los datos ausentes se excluyen y los pesos se renormalizan; nunca se puntúan como cero. La metodología es versionada y abierta: métricas v1.13.0, esquema v0.27.0 — metodología completa · wiki de métricas.

Cómo se sitúa un resultado dentro del registro general: estadísticas agregadasnpm.