Registro público
Informe de salud del softwareesquema 0.27.0 · métricas 1.13.0 · 2026-07-28 10:25 UTC

hostodo / odo-cli

GoSin licencia detectada★ 4 estrellas⑂ 0 forksdesde ene 2026Ver en GitHub ↗

hostodo/odo-cli tiene un índice de salud de 47 sobre 100, lo que lo sitúa en la banda En riesgo. Su puntuación más alta es AI Readiness (81/100) y la más baja, Community & Adoption (16/100). Se actualizó por última vez hace 13 días. Una sola persona concentra la mayor parte del trabajo reciente.

47
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.

47
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

HostodoOrganización
2 seguidores6 repositorios públicosdesde may 2021

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

Ecosistemas de paquetes

RegistroPaqueteVersiónDescargas / mesVersionesÚltima publicación
Gogithub.com/hostodo/odo-cli/v2v2.2.0-10hace 13 días

Métricas por categoría

Vitalidad

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

75Bueno · 22% del índice global
Cómo se puntúa
28.8/36Recencia de push — último push hace 13 días
9/36Cadencia de commits — 13/52 semanas con commits
17.1/18Volumen de commits — 79 commits en el último año
10/10OpenSSF Scorecard: Maintained — 16 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
Datos de entrada utilizados
commits_last_year79
human_commit_share1
days_since_last_push13
active_weeks_last_year13
Cómo se puntúa
27/27Publica versiones — 22 versiones publicadas
36/36Recencia de las versiones — última versión hace 13 días
27/27Cadencia de publicación — una versión cada ~11,3 días
0/10OpenSSF Scorecard: Signed-Releases — Project has not signed or included provenance with any releases.
Datos de entrada utilizados
releases_count22
latest_release_tagv2.2.0
releases_from_tagsno
days_since_latest_release13
mean_days_between_releases11,3

Comunidad y Adopción

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

16Crítico · 18% del índice global
Cómo se puntúa
7.7/60Estrellas — 4 estrellas
0/25Forks — 0 forks
0/15Observadores — 0 observadores
Datos de entrada utilizados
forks0
stars4
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

Sostenibilidad y Gobernanza

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

52Moderado · 24% del índice global
Cómo se puntúa
9/54Factor bus — la mitad de los commits recae en 1 contribuyente(s)
0.9/22.5Distribución de commits — el principal contribuyente firma el 96% de los commits
2.7/13.5Amplitud de contribuyentes — 2 contribuyentes
3/10OpenSSF Scorecard: Contributors — project has 1 contributing companies or organizations -- score normalized to 3
Datos de entrada utilizados
bus_factor1
contributors_sampled2
top_contributor_share0,962
Cómo se puntúa
0/46.8Resolución de issues — sin issues o sin datos
30.6/38.3Aceptación de PR — 12/15 PR decididos fusionados
1.5/15OpenSSF Scorecard: Code-Review — Found 3/25 approved changesets -- score normalized to 1
Datos de entrada utilizados
merged_prs12
open_issues0
closed_issues0
issue_closed_ratio
closed_unmerged_prs3
Excluidos de la puntuación (sin datos o no aplicable): Resolución de issues. Los pesos restantes se han renormalizado.
Cómo se puntúa
30/30Respaldo de la propiedad — propiedad de una organización
0/20Dominio verificado
3.4/25Alcance del propietario — 2 seguidores de hostodo
16.6/25Trayectoria — 6 repos públicos, cuenta de ~5 años
Datos de entrada utilizados
followers2
owner_typeOrganization
is_verified
owner_loginhostodo
public_repos6
account_age_days1900
Cómo se puntúa
25/25Publicado y resoluble — 1 paquete(s) en go
35/35Recencia de publicación — última publicación hace 13 días
20/20Historial de versiones — 10 versiones en el registro
20/20No obsoleto — activo, ni obsoleto ni retirado
Datos de entrada utilizados
packagesgithub.com/hostodo/odo-cli/v2
ecosystemsgo
any_deprecatedno
min_days_since_publish13

Calidad de Ingeniería

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

46En riesgo · 20% del índice global
Cómo se puntúa
24/24Flujos de trabajo de CI — 3 flujo(s) de trabajo
24/24Pruebas presentes
0/16Configuración de linter
0/9.6Hooks de pre-commit
0/6.4.editorconfig
2/20OpenSSF Scorecard: CI-Tests — 1 out of 8 merged PRs checked by a CI test -- score normalized to 1
Datos de entrada utilizados
has_ci
has_tests
has_editorconfigno
has_linter_configno
has_precommit_configno

Documentación

40En riesgo
Cómo se puntúa
30/30README
0/25Directorio de documentación
0/15Sitio de documentación / página del proyecto
0/10Descripción del repositorio
0/10Topics
10/10Wiki
Datos de entrada utilizados
topics
has_wiki
homepage
has_readme
has_docs_dirno
has_descriptionno

Seguridad

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

40En riesgo · 16% del índice global
Cómo se puntúa
6.8/7.5Binary-Artifacts — binaries present in source code
4.5/7.5Branch-Protection — branch protection is not maximal on development and all release branches
0.2/2.5CI-Tests — 1 out of 8 merged PRs checked by a CI test -- score normalized to 1
0/2.5CII-Best-Practices — no effort to earn an OpenSSF best practices badge detected
0.8/7.5Code-Review — Found 3/25 approved changesets -- score normalized to 1
0.8/2.5Contributors — project has 1 contributing companies or organizations -- score normalized to 3
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
7.5/7.5Maintained — 16 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
5/5Packaging — packaging workflow detected
0/5Pinned-Dependencies — dependency not pinned by hash detected -- score normalized to 0
0/5SAST — SAST tool is not run on all commits -- score normalized to 0
0/5Security-Policy — security policy file not detected
0/7.5Signed-Releases — Project has not signed or included provenance with any releases.
0/7.5Token-Permissions — detected GitHub workflow tokens with excessive permissions
6/7.5Vulnerabilities — 2 existing vulnerabilities detected
Datos de entrada utilizados
sourceopenssf_scorecard
checks_evaluated18
scorecard_versionv5.5.0
checks_inconclusive0
scorecard_aggregate4

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.

81Bueno · 0% del índice global
Cómo se puntúa
45/45Instrucciones para agentes — CLAUDE.md
0/15Documentación legible por máquinas (llms.txt)
40/40Historial de commits legible — 77 de 79 commits humanos declaran su intención (asunto estructurado o cuerpo explicativo)
Datos de entrada utilizados
has_llms_txtno
legible_history_share0,975
agent_instruction_filesCLAUDE.md
agent_instruction_max_bytes4142
Cómo se puntúa
18/18Arranque con un solo comando — Makefile
22/22Pruebas automatizadas
0/11Configuración de lint / formato
11/11Verificación estática de tipos — Go (tipado estático)
10/10Entorno reproducible — lockfile
10/10Práctica demostrada con agentes — 23 de los últimos 79 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
lockfilesgo.sum
has_dockerfileno
typed_language
bootstrap_filesMakefile
has_devcontainerno
has_linter_configno
typecheck_configs
agent_commit_share0,291
toolchain_manifestsgo.mod
dependency_bot_commit_share0
Cómo se puntúa
45/45Código verificable por tipos — Go (tipado estático)
55/55Tamaños de archivo manejables — 0/47 archivos fuente de más de 60 KB
Datos de entrada utilizados
primary_languageGo
largest_source_bytes25.017
source_files_sampled47
oversized_source_files0

Datos clave

4estrellas de GitHub
2contribuidores
79commits en los últimos 12 meses
13días desde el último push
22versiones publicadas
1factor bus
0issues abiertas
Goecosistemas de paquetes

Advertencias de recopilación de datos

  • Star history unavailable: GitHub GraphQL error: Resource not accessible by personal access token
  • GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository

Más detalle

OpenSSF Scorecard 4.0 / 10
4.0agregado

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-28 10:25 UTC

9Binary-Artifactsbinaries present in source code
6Branch-Protectionbranch protection is not maximal on development and all release branches
1CI-Tests1 out of 8 merged PRs checked by a CI test -- score normalized to 1
0CII-Best-Practicesno effort to earn an OpenSSF best practices badge detected
1Code-ReviewFound 3/25 approved changesets -- score normalized to 1
3Contributorsproject has 1 contributing companies or organizations -- score normalized to 3
10Dangerous-Workflowno dangerous workflow patterns detected
0Dependency-Update-Toolno update tool detected
0Fuzzingproject is not fuzzed
0Licenselicense file not detected
10Maintained16 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
10Packagingpackaging workflow detected
0Pinned-Dependenciesdependency not pinned by hash detected -- score normalized to 0
0SASTSAST tool is not run on all commits -- score normalized to 0
0Security-Policysecurity policy file not detected
0Signed-ReleasesProject has not signed or included provenance with any releases.
0Token-Permissionsdetected GitHub workflow tokens with excessive permissions
8Vulnerabilities2 existing vulnerabilities detected
Dependencias directas 10
RegistroPaqueteRestricción de versiónManifiesto
Gogithub.com/atotto/clipboardv0.1.4go.mod
Gogithub.com/briandowns/spinnerv1.23.2go.mod
Gogithub.com/charmbracelet/bubblesv0.21.1-0.20250623103423-23b8fd6302d7go.mod
Gogithub.com/charmbracelet/bubbleteav1.3.10go.mod
Gogithub.com/charmbracelet/huhv1.0.0go.mod
Gogithub.com/charmbracelet/lipglossv1.1.1-0.20250404203927-76690c660834go.mod
Gogithub.com/common-nighthawk/go-figurev0.0.0-20210622060536-734e95fb86bego.mod
Gogithub.com/google/uuidv1.6.0go.mod
Gogithub.com/spf13/cobrav1.10.1go.mod
Gogithub.com/zalando/go-keyringv0.2.6go.mod
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": 4261,
      "has_wiki": true,
      "homepage": null,
      "languages": {
        "Go": 223978,
        "Ruby": 1590,
        "Shell": 7833,
        "Makefile": 2992
      },
      "pushed_at": "2026-07-14T23:00:58Z",
      "created_at": "2026-01-26T05:05:00Z",
      "owner_type": "Organization",
      "updated_at": "2026-07-14T22:44:04Z",
      "description": null,
      "is_archived": false,
      "is_disabled": false,
      "license_spdx": null,
      "default_branch": "main",
      "license_spdx_raw": null,
      "primary_language": "Go",
      "significant_languages": [
        "Go"
      ]
    },
    "owner": {
      "blog": "https://hostodo.com",
      "name": "Hostodo",
      "type": "Organization",
      "login": "hostodo",
      "company": null,
      "location": null,
      "followers": 2,
      "avatar_url": "https://avatars.githubusercontent.com/u/84212751?v=4",
      "created_at": "2021-05-15T01:18:21Z",
      "is_verified": null,
      "public_repos": 6,
      "account_age_days": 1900
    },
    "license": {
      "state": "absent",
      "spdx_id": null,
      "raw_spdx": null,
      "file_present": false,
      "scorecard_found": false,
      "profile_has_license": false
    },
    "activity": {
      "releases": [
        {
          "tag": "v2.2.0",
          "kind": "minor",
          "published_at": "2026-07-14T23:01:12Z"
        },
        {
          "tag": "v2.1.2",
          "kind": "patch",
          "published_at": "2026-07-12T05:51:12Z"
        },
        {
          "tag": "v2.1.1",
          "kind": "patch",
          "published_at": "2026-06-01T03:00:12Z"
        },
        {
          "tag": "v2.1.0",
          "kind": "minor",
          "published_at": "2026-05-31T22:58:31Z"
        },
        {
          "tag": "v2.0.5",
          "kind": "patch",
          "published_at": "2026-04-30T02:47:14Z"
        },
        {
          "tag": "v2.0.4",
          "kind": "patch",
          "published_at": "2026-04-30T00:34:42Z"
        },
        {
          "tag": "v2.0.3",
          "kind": "patch",
          "published_at": "2026-04-17T03:41:14Z"
        },
        {
          "tag": "v2.0.2",
          "kind": "patch",
          "published_at": "2026-04-17T03:33:40Z"
        },
        {
          "tag": "v2.0.1",
          "kind": "patch",
          "published_at": "2026-04-04T19:26:29Z"
        },
        {
          "tag": "v2.0.0",
          "kind": "major",
          "published_at": "2026-04-04T05:02:34Z"
        },
        {
          "tag": "v1.2.3",
          "kind": "patch",
          "published_at": "2026-04-04T04:11:42Z"
        },
        {
          "tag": "v1.2.2",
          "kind": "patch",
          "published_at": "2026-04-04T03:59:19Z"
        },
        {
          "tag": "v1.2.1",
          "kind": "patch",
          "published_at": "2026-04-04T03:43:34Z"
        },
        {
          "tag": "v1.2.0",
          "kind": "minor",
          "published_at": "2026-04-04T03:20:38Z"
        },
        {
          "tag": "v1.1.1",
          "kind": "patch",
          "published_at": "2026-04-03T01:41:56Z"
        },
        {
          "tag": "v1.1.0",
          "kind": "minor",
          "published_at": "2026-04-03T01:28:31Z"
        },
        {
          "tag": "v1.0.0",
          "kind": "major",
          "published_at": "2026-04-02T02:32:43Z"
        },
        {
          "tag": "v0.1.4",
          "kind": "patch",
          "published_at": "2026-02-16T04:46:32Z"
        },
        {
          "tag": "v0.1.3",
          "kind": "patch",
          "published_at": "2026-01-27T04:36:40Z"
        },
        {
          "tag": "v0.1.2",
          "kind": "patch",
          "published_at": "2026-01-27T04:32:16Z"
        },
        {
          "tag": "v0.1.1",
          "kind": "patch",
          "published_at": "2026-01-27T04:29:27Z"
        },
        {
          "tag": "v0.1.0",
          "kind": "minor",
          "published_at": "2026-01-27T04:26:32Z"
        }
      ],
      "recent_commits": [
        {
          "oid": "b7dd9f17f81dfdd99dcb78e01fc67614349675fc",
          "body": "* ci: add semgrep scan on PRs to main\n\n* ci: pin semgrep image to 1.169.0\n\n* fix: suppress semgrep math/rand warning in hostname generation",
          "is_bot": false,
          "headline": "ci: add semgrep scan on PRs to main (#15)",
          "author_name": "Nathan Xavier Golez",
          "author_login": "neeythann",
          "committed_at": "2026-07-14T22:43:59Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "2c000669e4796e376a1cd5559b97547e406902c8",
          "body": "* fix: honor the --api-url flag and add --force-http for local dev\n\nThe --api-url persistent flag was registered but never read, so every\ncommand ignored it. Wire it through a root PersistentPreRunE into a\npkg/config override that takes precedence over HOSTODO_API_URL and the\nconfig file. An invalid\n[…]\nend never issued.\nSave the effective API URL to config after a successful login so the\nsession and config always agree on the backend.\n\n* fix(config): reject --force-http for the production API domain",
          "is_bot": false,
          "headline": "fix: honor the --api-url flag and add --force-http for local dev (#14)",
          "author_name": "Nathan Xavier Golez",
          "author_login": "neeythann",
          "committed_at": "2026-07-14T22:43:54Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "c58876149317c5eacc9117fed5c8bd0e4a40262d",
          "body": "Rewrites Go module/import paths and release ldflags for v2 semantic import versioning.",
          "is_bot": false,
          "headline": "refactor: rename module to github.com/hostodo/odo-cli/v2",
          "author_name": "Nathan Xavier Golez",
          "author_login": "neeythann",
          "committed_at": "2026-07-12T05:48:44Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3447d58fddcc2140aceef099bd500d04cd1c7475",
          "body": "The Release (Manual) workflow pushed the tag with the default GITHUB_TOKEN,\nand tags pushed by GITHUB_TOKEN don't trigger other workflows (GitHub's\nanti-recursion safeguard). So release.yml (GoReleaser) silently never ran —\nevery release required a manual tag delete + re-push from local creds to\nfir\n[…]\n after release-version.sh creates the\ntag on HEAD. One dispatch click now tags AND publishes. release.yml is kept\nfor manually/locally pushed tags and documented so the two paths don't\ndouble-release.",
          "is_bot": false,
          "headline": "ci: run GoReleaser inside the dispatch job (self-chaining release)",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-06-20T04:41:42Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "42a205e6fbe6d1e562020dee48243ffe4aa910a0",
          "body": "feat: send CLI PostHog attribution headers",
          "is_bot": false,
          "headline": "Merge pull request #12 from hostodo/feat/posthog-cli-attribution",
          "author_name": "Hassan Bazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-06-01T02:57:51Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0edf6a14fd21eb15078cbfd4090f229204132ac4",
          "body": null,
          "is_bot": false,
          "headline": "feat: send CLI PostHog attribution headers",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-06-01T02:53:22Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "dee041241e194c0420e1501ac2dc1e89692f9501",
          "body": "docs: bump version badge to v2.1.0",
          "is_bot": false,
          "headline": "Merge pull request #10 from hostodo/chore/badge-v2.1.0",
          "author_name": "Hassan Bazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-05-31T22:54:29Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "9fb887502e1a719428b671c27a90241f68954fc4",
          "body": null,
          "is_bot": false,
          "headline": "docs: bump version badge to v2.1.0",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-05-31T22:54:15Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e9e246be3f7fc14dfab2227e2d8f0a55cea18d4c",
          "body": "feat: support ticket commands (list, open, reply, show, departments)",
          "is_bot": false,
          "headline": "Merge pull request #9 from hostodo/feat/tickets",
          "author_name": "Hassan Bazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-05-31T22:53:06Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "6eb77df764a5aa9a229b3950342b23d3d96a8e44",
          "body": "…t/departments, fix stdin portability, add show/departments to help text",
          "is_bot": false,
          "headline": "fix: address CodeRabbit review — add json/simple flags to tickets lis…",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-05-29T02:58:09Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "6f7644bdb60ae04d44c3c3f97f5fd081bef108cb",
          "body": null,
          "is_bot": false,
          "headline": "feat(deploy): prompt for promo code interactively in wizard",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-05-29T02:16:13Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a4e2f6f35b226841774729c06fac207602c3c389",
          "body": null,
          "is_bot": false,
          "headline": "feat: add support ticket commands (list, open, reply, show, departments)",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-05-29T01:59:06Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "82cc62210d67e07ca8cc2e73aa9f4d7660e7ac52",
          "body": "- Version badge 2.0.0 → 2.0.5\n- Go badge 1.24 → 1.25\n- Add --promo flag to deploy section with examples\n- Fix region examples: DET01/LV01/TPA01\n- Fix plan examples: EPYC-2G1C32GN\n- reinstall: remove 'Coming soon', document flags\n- Remove stale token.enc / AES references\n- HOSTODO_API_URL must be https://\n- Fix download filenames to match actual GoReleaser output",
          "is_bot": false,
          "headline": "docs: update README for v2.0.5",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-04-30T03:31:30Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c7f4fbf7f5cc6054105c7df6b386ff3c90384a55",
          "body": "…tion\n\n- Add 20 tests in pkg/api/client_test.go covering:\n  - GetQuote: promo applied, no promo, invalid promo rejected (400), promo\n    field present in request body\n  - ListPlans: filters disabled + out-of-stock, empty results\n  - ListRegions: filters out-of-stock\n  - ListTemplates: returns all\n  \n[…]\nson.Unmarshal to fail silently and always fall through to ErrTokenExpired.\n  Fix: drop the Code field from the inline struct (only Detail is needed).\n\n- Add auth.ResetDefaultStore() for test isolation",
          "is_bot": false,
          "headline": "test: add httptest-based API client tests + fix revoked session detec…",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-04-30T01:38:24Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "b48092007d094fffa949b4ff4c611c2cd5be3147",
          "body": "…ken encryption\n\n- Bump toolchain to go1.25.9 (fixes 10 stdlib CVEs: 3x crypto/tls, 2x\n  crypto/x509, net/url, os)\n- Validate HOSTODO_API_URL must be https:// — plain HTTP would send Bearer\n  tokens to attacker-controlled servers\n- Replace hostname-derived AES encryption in fallback token file with \n[…]\n56(hostname)) was not secret and\n  provided no protection beyond filesystem permissions\n- Fix copyFile in MigrateConfigDir to hardcode 0600 instead of inheriting\n  potentially loose source permissions",
          "is_bot": false,
          "headline": "security: upgrade to go1.25.9, enforce HTTPS on API URL, drop fake to…",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-04-30T01:18:10Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "c9fe2770c56423723a92c3d872fcba8567c847a6",
          "body": "…er output",
          "is_bot": false,
          "headline": "fix(auth): replace pkg/browser with native exec to suppress multiplex…",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-04-30T00:32:42Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "73ec6847e927ed003918fc2e0f9e0577d1f47e36",
          "body": "- Add --promo flag to deploy command\n- Pass promo code to quote API so discounted price shows in confirmation\n- Pass promo code through to deploy order request\n- Show 'Promo: CODE (applied)' line in deploy summary when promo is set\n- Add Promocode field to QuoteRequest struct\n\nEnables use of discount codes at deploy time:\n  odo deploy --promo LETCLI",
          "is_bot": false,
          "headline": "feat: add --promo flag to odo deploy",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-04-22T04:39:18Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "342ee25bc9029e355b9dcc889dabd0e1c7e74b11",
          "body": "- POST /client/instances/{id}/reinstall/ with template_id + optional ssh_key_id\n- Interactive OS template selection (reuses deploy picker) with --os, --ssh-key, --yes flags\n- 10-minute timeout spinner since backend stop+delete+rebuild is synchronous\n- Displays new root password and SSH command on completion\n- Available as `odo instances reinstall <hostname>` and [i] in TUI detail view",
          "is_bot": false,
          "headline": "feat(cli): implement instance reinstall command",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-04-17T03:39:41Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0c204cce4be6e6915017cbcf5e81ee8174adfa9b",
          "body": "- TUI detail view now supports start, stop, force stop, restart, force\n  restart, and rename (inline text input) without leaving the TUI\n- Removed post-deploy \"Connect now?\" prompt — deploy just prints the\n  success card and returns\n- SSH command shows \"OS is still being installed\" message when connection\n  fails within 10 minutes of instance creation instead of falling through\n  to sshpass auth errors",
          "is_bot": false,
          "headline": "feat(tui): add instance actions in detail view, drop auto-SSH on deploy",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-04-17T03:32:01Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a778ecdfa915df70671111d0f316a47ced6c4789",
          "body": null,
          "is_bot": false,
          "headline": "docs: update docs link to hostodo.com/docs/cli",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-04-05T04:50:18Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c2c72d79b9abe75c100d00f5ea78007a9a233cf2",
          "body": null,
          "is_bot": false,
          "headline": "chore: rename repo from cli to odo-cli",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-04-05T04:32:03Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "2517a8943edfe03fe62829ffca312aec145d6135",
          "body": null,
          "is_bot": false,
          "headline": "feat: add post-install completion setup caveats to brew formula",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-04-04T19:24:57Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f1389ed102a95bd907acecb5fa28c5fb283aa478",
          "body": null,
          "is_bot": false,
          "headline": "docs: update README and CLAUDE.md for odo rename",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-04-04T19:20:34Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "1a14cd26730f7a73bb4749b08d38c038ca742d62",
          "body": "- Rename binary from hostodo → odo (Makefile, .goreleaser.yml)\n- Create cmd/instances/ package with all instance subcommands\n- Add odo instances list/ssh/status/start/stop/restart/rename/deploy\n- Add odo instances reinstall stub (prints not yet implemented)\n- Keep hidden root-level shortcuts (odo li\n[…]\nrst run\n- Migrate keychain service name hostodo-cli → odo-cli with fallback\n- Update all help text from hostodo → odo throughout\n- Fix stale ssh_test.go expectations (StrictHostKeyChecking=accept-new)",
          "is_bot": false,
          "headline": "feat(cli): rename binary to odo with instances namespace",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-04-04T05:00:10Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "28137c54feccc2b7744b1ab1f8b5436b0279524f",
          "body": "none",
          "is_bot": false,
          "headline": "feat: auto-install shell completions via Homebrew",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-04-04T04:04:25Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ccdaae125f9c8d8709c7637b90f36d799031a3a9",
          "body": "Use StrictHostKeyChecking=accept-new so SSH auto-accepts unknown host\nkeys (fresh deploys) while still rejecting changed keys for security.\n\nnone",
          "is_bot": false,
          "headline": "fix: auto-accept host keys for newly deployed instances",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-04-04T03:57:47Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3dddc5ffa823a1562ab567cadef2a4bc4e9883e5",
          "body": "Without a limit param, DRF returns only the default page size.\nMatch the frontend behavior by requesting up to 200 plans.\n\nnone",
          "is_bot": false,
          "headline": "fix: add limit=200 to plans API query",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-04-04T03:42:56Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "976a5c12a734b0beac486aafae72752d4fc77340",
          "body": "Match the frontend behavior — only show plans whose plan_category_id\nis associated with the selected region. This hides promotional/legacy\nplans (e.g. 2024BF) that aren't assigned to current regions.\n\nnone",
          "is_bot": false,
          "headline": "fix: filter deploy plans by region's plan categories",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-04-04T03:32:51Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e22c24ed978167f81c9247561f0740233c191513",
          "body": "Switch from AlecAivazis/survey to charmbracelet/huh for all interactive\nprompts. Pressing Escape now cleanly cancels any prompt instead of\nrequiring Ctrl-C.\n\nnone",
          "is_bot": false,
          "headline": "feat: replace survey with huh for Escape key support",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-04-04T03:19:46Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "03596524df0d7d9c4df8e7bea4d313cfa9046790",
          "body": "The deploy command was immediately checking invoice status after order\ncreation, but Stripe webhooks take a few seconds to arrive. Now polls\nthe invoice status for up to 15 seconds before reporting payment failure.\n\nnone",
          "is_bot": false,
          "headline": "fix: poll for Stripe webhook before failing payment",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-04-03T01:41:46Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "061766f91cc70388a8980e41002c9d5d46d955ea",
          "body": "feat: add billing cycle support to deploy command",
          "is_bot": false,
          "headline": "Merge pull request #7 from hostodo/fix/billing-cycle-support",
          "author_name": "Hassan Bazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-04-03T01:28:19Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "dc2463ec3faf8103d771c68c3931298bb54a5785",
          "body": "- Add billing cycle selection prompt (monthly, annually, semiannually, etc.)\n- Filter plans by selected billing cycle — hides plans with no pricing for that cycle\n- Fix QuoteRequest to send plan_id (int) instead of plan name (backend expects plan_id)\n- Display prices with correct suffix (/mo, /yr, /6mo, etc.)\n- Add --billing-cycle flag for scripted/JSON mode\n- Show billing cycle in deploy confirmation summary\n\nnone",
          "is_bot": false,
          "headline": "feat: add billing cycle support to deploy command",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-04-03T01:22:58Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0f57d205de0fc49bec264de9bbc6b030642bd568",
          "body": "feat: add instance/instances aliases for list",
          "is_bot": false,
          "headline": "Merge pull request #6 from hostodo/feat/instance-alias",
          "author_name": "Hassan Bazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-04-02T23:24:35Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "80e7f260a7c40e8db0be5e75b45c0d6dc4fc78af",
          "body": "Allows `hostodo instance` and `hostodo instances` as intuitive\nalternatives to `hostodo list`.\n\nnone",
          "is_bot": false,
          "headline": "feat: add instance/instances as aliases for list command",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-04-02T03:42:37Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3805986343c0c006e25755cf8b7e9530e3b5f9f0",
          "body": "feat: add manual release dispatch with semver bump",
          "is_bot": false,
          "headline": "Merge pull request #4 from hostodo/feature/manual-release-dispatch",
          "author_name": "Hassan Bazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-03-06T05:45:28Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "9e7bfbca5c57bd9a27c5e0217be35479bbd6d6c9",
          "body": null,
          "is_bot": false,
          "headline": "feat(release): add manual dispatch semver tagging workflow",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-02-25T04:24:06Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ef1a545d40614e5f69244346d37426f8c92d2f08",
          "body": "…econfig\n\nDeploy progress, SSH password fallback, and API fixes",
          "is_bot": false,
          "headline": "Merge pull request #3 from hostodo/feature/cli-ordering-and-command-r…",
          "author_name": "Hassan Bazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-02-24T05:48:11Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "729775815af3f56ea8b86d11a609c7a27769fef8",
          "body": "- Fix potential panic in keys.go from unchecked fmt.Sscanf result\n- Redact DefaultPassword from JSON output to prevent credential leakage\n- Set PaymentMethodID on deploy request so charges route to correct card\n- Re-exec SSH as subprocess from deploy to avoid os.Exit bypassing cleanup\n- Fix GetInsta\n[…]\nshpass on exit code 255\n- Add doRequestWithTimeout for reboot endpoint\n- Improve restart polling to handle in-place QEMU reboots\n\nCo-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Fix critical and major PR review issues",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-02-24T05:43:23Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "4538ca887ac049d912f87a0252da7d88e2468527",
          "body": "Allows users to rename VPS instances from the CLI via\n`hostodo rename <hostname> <new-hostname>`. Uses the existing\nPATCH /client/instances/{id}/update_info/ backend endpoint.\nValidates the new hostname client-side before making the API call.\n\nCo-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Add `hostodo rename` command for renaming instances",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-02-24T05:00:39Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "668980f1942aac356f9d4f31272f18afc030ba04",
          "body": "- Table persists in terminal scrollback on quit\n- Remove Power column from list (requires per-instance API call, too slow)\n- Fetch live power status when entering instance detail view\n- Add [c] SSH Connect action in detail view\n- Remove empty \"Updated\" field from detail view (not in API response)\n- Remove ID column truncation to show full instance IDs\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Improve list TUI: persist scrollback, drop power column, add SSH connect",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-02-24T03:41:31Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "d1215be69329f2f83fee372023d5b032a4adcaef",
          "body": "Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Hide --api-url flag from help output",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-02-24T00:20:17Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "576300e52db3c3d1b2820ed7585b6a0401679256",
          "body": "- Fix --force flag ignored in stop/restart (now passed to API)\n- Fix SSH BatchMode for sshpass password fallback\n- Fix URL parameter injection in invoice status filter\n- Fix findTemplate/findRegion ambiguous substring matching\n- Refactor deploy.go: extract selectTemplate, selectRegion, selectPlan,\n \n[…]\nHFingerprint)\n  - cmd/deploy_test.go (find*, mapEventMessage, formatRAM/BW)\n  - cmd/ssh_test.go (buildSSHArgs)\n- Apply gofmt formatting fixes\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Fix review issues, refactor deploy command, and add unit tests",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-02-22T02:40:15Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "56c81008718f074d9d47dd6e941d1ea0539c7f8b",
          "body": "- Replace deprecated ioutil.ReadFile with os.ReadFile (keys.go)\n- Remove deprecated rand.Seed call (hostname.go)\n- Use SSHPASS env var instead of -p flag to avoid password in process list (ssh.go)\n- Add confirmation prompt and --yes flag to pay command (pay.go)\n- Remove time.After timer leak from bo\n[…]\ny.go)\n- Add exact-first-then-substring matching for findTemplate/findRegion (deploy.go)\n- Add RFC 1123 hostname length validation (hostname.go)\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Fix review issues: deprecated APIs, security, UX, and performance",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-02-21T20:21:57Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "65c5c4742868c20589758563e794c315b721bbf8",
          "body": "README was documenting the old nested command structure (hostodo instances\nlist/get/reboot) and email/password auth. Updated to reflect current flat\ncommands (list/status/restart), OAuth device flow, keychain token storage,\nand all new commands (deploy, ssh, invoices, pay, keys, whoami, sessions).\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Add CLAUDE.md and sync README with actual implementation",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-02-18T05:05:19Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "29e664b13047fac4cea30f5caf322a9d8ec171c2",
          "body": "- Add granular provisioning progress with event polling during deploy\n- Add sshpass fallback when SSH key auth fails and instance has default password\n- Fix billing API paths to use /v1/billing/ prefix\n- Fix power status parsing to unwrap instance detail response\n- Replace generic power control with\n[…]\n, payment methods pagination, and event log models\n- Add DefaultPassword field to Instance model\n- Use json.Number for quote response amounts\n\nCo-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Add deploy provisioning progress, SSH password fallback, and API fixes",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-02-18T05:02:04Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "9e08f77ebd33f0c95fb45a223077b173fdf60fe4",
          "body": "FormatSSHKeysTable used interface{} with a local type assertion that\ncould never match callers from other packages. Export SSHKeyDisplay\nfrom the ui package so cmd/keys.go can use it directly.\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(04-02): export SSHKeyDisplay type to fix keys list runtime bug",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-02-17T03:27:34Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "de6f78bb28e96837e1113d8961621332f9d31d09",
          "body": "- Add keys command with list/add/remove subcommands\n- Add FormatSSHKeysTable to ui/formatters.go\n- Integrate SSH key selection into deploy flow after hostname step\n- Deploy auto-selects when one key, shows picker for multiple, skips for none\n- Add --ssh-key flag to deploy command for non-interactive\n[…]\nupports inline key or --file flag, shows confirmation with fingerprint\n- Keys remove shows fingerprint and requires y/n confirmation\n- Register keys command in root.go under SSH Key Management section",
          "is_bot": false,
          "headline": "feat(04-02): add keys command and deploy SSH key integration",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-02-17T00:20:55Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "6ebad53c2a61b254febf2d72621f8328a6259a1c",
          "body": "- Add SSHKey struct to models.go\n- Create sshkeys.go with ListSSHKeys, AddSSHKey, DeleteSSHKey methods\n- Create utils/ssh.go with CalculateSSHFingerprint function\n- Fingerprint uses SHA256 with RawStdEncoding (no padding) to match OpenSSH format",
          "is_bot": false,
          "headline": "feat(04-02): add SSH key API models, methods, and fingerprint utility",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-02-17T00:18:57Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "072164d0d04cce597a861ade8745c66e69f3bfc1",
          "body": "- Create invoicesCmd with --status flag for filtering\n- Create payCmd that charges immediately without confirmation\n- Add FormatInvoicesTable with overdue detection (unpaid + past due)\n- Add FormatPaymentReceipt with green bordered lipgloss box\n- Handle payment failures with dashboard link\n- Register both commands in root.go billing section\n- Update root help text to include billing commands",
          "is_bot": false,
          "headline": "feat(04-01): add invoice and pay commands with formatters",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-02-17T00:15:27Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "4a7b110ba97255f2736f47a1567829b0a6b109e0",
          "body": "- Add Invoice struct with InvoiceNumber, Status, DueDate, Subtotal, Instances\n- Add InvoicesResponse for paginated response handling\n- Add PaymentResponse with flexible payment integration fields\n- Create invoices.go with ListInvoices(status) and PayInvoice(invoiceNumber)\n- Both methods follow existing API pattern from deploy.go",
          "is_bot": false,
          "headline": "feat(04-01): add invoice and payment API models and methods",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-02-17T00:14:06Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "fa7d7d75d675fb69187934e0e3aef29d4feae3b6",
          "body": "- Added deploy command to root command registration\n- Updated help text with new Deployment section\n- Deploy appears between Authentication and Instance Management sections",
          "is_bot": false,
          "headline": "feat(03-02): register deploy command in root",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-02-16T21:06:50Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ec04e6a8b71ad6db4edd7c1134087a2e385d30f7",
          "body": "- Interactive OS/region/plan selection with arrow-key menus\n- Auto-generated hostname with Docker-style adjective-noun pattern\n- Custom hostname support with validation\n- Payment confirmation showing card details and pricing\n- Step-by-step provisioning progress with spinners and checkmarks\n- Boxed result card with instance details\n- JSON output mode for automation\n- SSH connection prompt after successful deploy\n- Flags: --os, --region, --plan, --hostname, --yes, --json",
          "is_bot": false,
          "headline": "feat(03-02): implement deploy command with full interactive flow",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-02-16T21:06:23Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3ddccd83823247b36b82d5654af797fd71b8e42b",
          "body": "- Implement Generate function with adjective-noun pattern\n- 80 adjectives and 80 nouns with mixed tone (neutral/techy + fun/playful)\n- Collision detection with 10 retry attempts\n- Fallback to 4-digit suffix after max retries\n- Implement Validate function with relaxed rules\n- Accept letters, numbers, and hyphens (cannot start/end with hyphen)\n- No length limit per user decision",
          "is_bot": false,
          "headline": "feat(03-01): create hostname generator package",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-02-16T21:01:58Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a3dfa94c9479c0802e682b9625e08774555ce9cc",
          "body": "- Add survey/v2 and spinner dependencies to go.mod\n- Add Region, PaymentMethod, Quote, and Deploy models\n- Add Enabled and OutOfStock fields to Plan model\n- Create deploy.go with 8 API methods for deployment flow\n- ListPlans, ListRegions, ListTemplates filter out unavailable options\n- GetDefaultPaymentMethod retrieves customer default payment method\n- GetQuote and CreateDeployOrder handle pricing and provisioning\n- CheckHostnameExists prevents hostname collisions",
          "is_bot": false,
          "headline": "feat(03-01): add API models and deploy endpoint methods",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-02-16T21:01:17Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "5487b5783d361e7a6421f189eb8fe6ab5b1a5860",
          "body": "- Created cmd/completion.go for generating bash/zsh/fish completions\n- Generates completion scripts with dynamic hostname completion\n- Provides installation instructions for each shell type\n- Validates shell argument (bash, zsh, fish only)\n- Uses cobra's GenBashCompletionV2, GenZshCompletion, GenFishCompletion\n- Registered completion command in root.go",
          "is_bot": false,
          "headline": "feat(02-02): add shell completion generation command",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-02-16T18:40:26Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b51897743275c8cc42b998568cb1f1c5c0a7f0f4",
          "body": "…passthrough\n\n- Created cmd/ssh.go with hostname resolution via resolver package\n- Auto-detects SSH user from instance template metadata, defaults to root\n- User can override SSH user with --user/-u flag\n- Everything after -- is forwarded to ssh binary as extra flags\n- Checks instance power status, shows error with hint if stopped\n- Executes system ssh binary with stdin/stdout/stderr passthrough\n- Registered ssh command in root.go",
          "is_bot": false,
          "headline": "feat(02-02): add SSH command with hostname resolution and system ssh …",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-02-16T18:39:42Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "18d5e89c3053ac7bd4d02cd83472634bc365ecd0",
          "body": "…olver\n\n- Create top-level list command with ls/ps aliases (Docker muscle memory)\n- Create top-level start command with hostname resolution\n- Create top-level stop command with hostname resolution\n- Create top-level restart command (renamed from reboot) with hostname resolution\n- Create top-level st\n[…]\nces group\n- Delete cmd/instances/ directory completely\n- All hostname-accepting commands use resolver.CompleteHostname for shell completions\n- Commands accept hostname, hostname prefix, or instance ID",
          "is_bot": false,
          "headline": "feat(02-01): flatten instance commands to top-level with hostname res…",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-02-16T18:35:32Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "6017d6d96bf639d43d16c8f47af3d7dad6f3b86e",
          "body": "…d ID fallback\n\n- Add ResolveInstance function with exact match, prefix match, and instance ID fallback\n- Add CompleteHostname for shell completions\n- Add GetInstancesCached with 3-second TTL for completion performance\n- Add InvalidateCache for cache management",
          "is_bot": false,
          "headline": "feat(02-01): create hostname resolver package with prefix matching an…",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-02-16T18:33:18Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "07c0aa6ab66dd73d8541b7a2369c22e46c106707",
          "body": "- Update formatCodeWithDash to format 12-char codes as XXXX-XXXX-XXXX\n- Add ErrSessionRevoked sentinel error for distinct revoked handling\n- Parse 401 response body to distinguish revoked vs expired sessions\n- Update CLISession model to match backend field renames (login_ip, revoked_at)\n- Fix sessions.go IPAddress reference to LoginIP after model update\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(01-01): update CLI for 12-char codes and revoked session handling",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-02-16T15:03:58Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "f30101b53f8e7e17a5061e406626ca50ffb3cb33",
          "body": null,
          "is_bot": false,
          "headline": "docs: create roadmap (3 phases)",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-02-16T04:59:06Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ff99df0e6ee557348ea7a629d72c95071c4aba67",
          "body": null,
          "is_bot": false,
          "headline": "docs: define v1 requirements",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-02-16T04:55:40Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ddcbd15ccc32900f7adbb2db33502926b6689053",
          "body": "The correct production API URL is api.hostodo.com, not console.hostodo.com\n\nCo-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: revert default API URL to api.hostodo.com",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-02-16T04:44:59Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "8867acde35307d507bc5eb1aa7fb38ee29034955",
          "body": null,
          "is_bot": false,
          "headline": "docs: complete project research",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-02-16T04:44:30Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d4a69f68794bc0878e7ad35cf3863beac82715e7",
          "body": null,
          "is_bot": false,
          "headline": "chore: add project config",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-02-16T04:36:40Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "33fc2b811623a1b992fa551e3d3dc59b745d5d00",
          "body": null,
          "is_bot": false,
          "headline": "docs: initialize project",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-02-16T04:32:07Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "25a7907d786ab33d71378bb3ef1f31a3c6c60195",
          "body": "Reorganize dependencies after build\n\nCo-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore: update go dependencies",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-01-27T04:43:56Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "df384b45adce008c5d12ad62b3ac0cb800f7194e",
          "body": "Change default API URL from api.hostodo.com to console.hostodo.com\nto match production environment.\n\nCo-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: update default API URL to console.hostodo.com",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-01-27T04:34:56Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "ee7bc787544905127b3e16e0658c27e810226f5b",
          "body": "Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: set universal binary name to 'hostodo'",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-01-27T04:30:47Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "4fef903008bf5580514a697155eb2ca666b4f84e",
          "body": "Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: set Homebrew formula name to 'hostodo'",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-01-27T04:27:50Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "72f434bf4937764889611f1f4c87615fc635ea7c",
          "body": "Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: enable TAP_GITHUB_TOKEN for Homebrew formula publishing",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-01-27T04:24:52Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "c6cf71ee5145c0cf0178ebb1d64dea8ffb97d012",
          "body": "Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: update GoReleaser config to v2 syntax",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-01-27T04:22:31Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "b81f08d0ca0d0f30b0a577705a1ede749e89d824",
          "body": "- Add GoReleaser configuration for automated releases\n- Add GitHub Actions workflow for release automation\n- Add Makefile for build automation\n- Add Homebrew formula template\n- Update README with installation instructions\n- Add version information to CLI (version, commit, date)\n- Add comprehensive setup and release documentation\n\nCo-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: add Homebrew distribution support",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-01-27T04:20:29Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "36ec5d3b41118e06c01d00cf8d53dc89743b5cd4",
          "body": "Fix whoami command calling non-existent /client/user/ endpoint.\nThe correct endpoint is /v1/auth/ (used by ValidateSession).\n\nChange GetCurrentUser() to delegate to ValidateSession() since\nthey both do the same thing: retrieve authenticated user info.\n\nThis fixes \"404 Not Found\" error when running 'hostodo whoami'.\n\nCo-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(auth): correct GetCurrentUser endpoint to /v1/auth/",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-01-27T04:07:45Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "49d545c567f2669af43320e2e43d067136a02531",
          "body": "Add device ID tracking system that generates and persists a unique UUID\nper machine in the CLI config file. This enables true device tracking\nacross login sessions and better session management.\n\nChanges:\n- Add DeviceID field to Config struct\n- Implement GetOrCreateDeviceID() to generate/persist UUI\n[…]\nogle/uuid dependency\n\nDevice ID is generated once per machine and stored in ~/.config/hostodo/config.json\nfor future authentication requests.\n\nCo-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(auth): implement persistent UUID-based device identification",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-01-26T05:09:38Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "0cfcc9da536606e6d0832dd30dec00c02857b132",
          "body": "- Add 'hostodo auth sessions' command to list active CLI sessions\n- Add 'hostodo sessions' convenience alias\n- Update logout to use DELETE /v1/cli-sessions/current/\n- Add CLISession models and API client methods\n- Improve command aliasing in root.go\n\nFeatures:\n- List all active CLI sessions with device names, IPs, dates\n- Session table view with formatted output\n- API integration with /v1/cli-sessions/ endpoints\n\nCo-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(auth): add CLI session management commands",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-01-26T04:40:59Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "90b80fde699f92bbde000f375ad4eefe86200ab9",
          "body": "…rowser\n\n- Add 'Press Enter to open browser' prompt\n- Display copy-pastable code in italics below ASCII art\n- User must confirm before browser opens\n- Prevents unexpected browser behavior\n\nCo-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(login): improve UX - wait for user confirmation before opening b…",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-01-26T04:39:34Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "53fc97de92e9ada473175ce5b272ca244d5fbc95",
          "body": "Previously, 'hostodo login' would block users who were already authenticated,\nrequiring them to run 'hostodo logout' first. This was inconvenient.\n\nNow:\n- Login command always proceeds, even if already authenticated\n- Displays warning that continuing will replace current session\n- Matches behavior o\n[…]\nhat allow re-auth\n\nThis provides better UX for users who want to:\n- Switch accounts\n- Refresh their authentication\n- Recover from auth issues\n\nCo-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(login): allow re-authentication without requiring logout",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-01-26T04:12:47Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "036e03837626efead9adb151d626d4d3433ff02b",
          "body": "- Add os.Exit(1) to exitWithError function\n- Import os package\n- Prevents crash when API returns error",
          "is_bot": false,
          "headline": "fix(03.1): prevent nil pointer crash in instances list error handling",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-01-25T00:01:08Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "74d3e9a171b1bb06bf8c1bf06b2e258220d2c101",
          "body": null,
          "is_bot": false,
          "headline": "wip",
          "author_name": "hbazzi",
          "author_login": "hassan-bazzi",
          "committed_at": "2026-01-24T21:39:17Z",
          "body_truncated": false,
          "is_coding_agent": false
        }
      ],
      "releases_count": 22,
      "commits_last_year": 79,
      "latest_release_at": "2026-07-14T23:01:12Z",
      "latest_release_tag": "v2.2.0",
      "releases_from_tags": false,
      "days_since_last_push": 13,
      "active_weeks_last_year": 13,
      "days_since_latest_release": 13,
      "mean_days_between_releases": 11.3
    },
    "community": {
      "has_readme": true,
      "has_license": false,
      "has_description": false,
      "has_contributing": false,
      "health_percentage": 25,
      "has_issue_template": false,
      "has_code_of_conduct": false,
      "has_pull_request_template": false
    },
    "ecosystem": {
      "packages": [
        {
          "name": "github.com/hostodo/odo-cli/v2",
          "exists": true,
          "license": null,
          "keywords": [],
          "ecosystem": "go",
          "matches_repo": true,
          "registry_url": "https://pkg.go.dev/github.com/hostodo/odo-cli/v2",
          "is_deprecated": false,
          "latest_version": "v2.2.0",
          "repository_url": "https://github.com/hostodo/odo-cli",
          "versions_count": 10,
          "total_downloads": null,
          "dependents_count": null,
          "deprecation_note": null,
          "maintainers_count": null,
          "monthly_downloads": null,
          "first_published_at": null,
          "latest_published_at": "2026-07-14T22:43:59Z",
          "latest_version_yanked": null,
          "days_since_latest_publish": 13
        }
      ]
    },
    "popularity": {
      "forks": 0,
      "stars": 4,
      "watchers": 0,
      "fork_history": {
        "days": [],
        "complete": true,
        "collected": 0,
        "total_forks": 0
      },
      "star_history": null,
      "open_issues_and_prs": 0
    },
    "ai_readiness": {
      "has_nix": false,
      "example_dirs": [],
      "has_llms_txt": false,
      "has_dockerfile": false,
      "has_mcp_signal": false,
      "bootstrap_files": [
        "Makefile"
      ],
      "api_schema_files": [],
      "has_devcontainer": false,
      "typecheck_configs": [],
      "toolchain_manifests": [
        "go.mod"
      ],
      "largest_source_bytes": 25017,
      "source_files_sampled": 47,
      "oversized_source_files": 0,
      "agent_instruction_files": [
        "CLAUDE.md"
      ],
      "agent_instruction_max_bytes": 4142
    },
    "dependencies": {
      "manifests": [
        "go.mod"
      ],
      "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": [
        "go"
      ],
      "dependencies": [
        {
          "name": "github.com/atotto/clipboard",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v0.1.4"
        },
        {
          "name": "github.com/briandowns/spinner",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v1.23.2"
        },
        {
          "name": "github.com/charmbracelet/bubbles",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v0.21.1-0.20250623103423-23b8fd6302d7"
        },
        {
          "name": "github.com/charmbracelet/bubbletea",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v1.3.10"
        },
        {
          "name": "github.com/charmbracelet/huh",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v1.0.0"
        },
        {
          "name": "github.com/charmbracelet/lipgloss",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v1.1.1-0.20250404203927-76690c660834"
        },
        {
          "name": "github.com/common-nighthawk/go-figure",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v0.0.0-20210622060536-734e95fb86be"
        },
        {
          "name": "github.com/google/uuid",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v1.6.0"
        },
        {
          "name": "github.com/spf13/cobra",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v1.10.1"
        },
        {
          "name": "github.com/zalando/go-keyring",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v0.2.6"
        }
      ],
      "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": 12,
        "open_issues": 0,
        "closed_ratio": null,
        "closed_issues": 0,
        "closed_unmerged_prs": 3
      },
      "bus_factor": 1,
      "bot_contributors": 0,
      "top_contributors": [
        {
          "type": "User",
          "login": "hassan-bazzi",
          "commits": 76,
          "avatar_url": "https://avatars.githubusercontent.com/u/17152251?v=4"
        },
        {
          "type": "User",
          "login": "neeythann",
          "commits": 3,
          "avatar_url": "https://avatars.githubusercontent.com/u/89695588?v=4"
        }
      ],
      "contributors_sampled": 2,
      "top_contributor_share": 0.962
    },
    "quality_signals": {
      "has_ci": true,
      "has_tests": true,
      "ci_workflows": [
        "release-dispatch.yml",
        "release.yml",
        "semgrep.yml"
      ],
      "has_docs_dir": false,
      "linter_configs": [],
      "has_editorconfig": false,
      "has_linter_config": false,
      "has_precommit_config": false
    },
    "security_signals": {
      "lockfiles": [
        "go.sum"
      ],
      "scorecard": {
        "checks": [
          {
            "name": "Binary-Artifacts",
            "score": 9,
            "reason": "binaries present in source code",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#binary-artifacts"
          },
          {
            "name": "Branch-Protection",
            "score": 6,
            "reason": "branch protection is not maximal on development and all release branches",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#branch-protection"
          },
          {
            "name": "CI-Tests",
            "score": 1,
            "reason": "1 out of 8 merged PRs checked by a CI test -- score normalized to 1",
            "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": 1,
            "reason": "Found 3/25 approved changesets -- score normalized to 1",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#code-review"
          },
          {
            "name": "Contributors",
            "score": 3,
            "reason": "project has 1 contributing companies or organizations -- score normalized to 3",
            "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": 10,
            "reason": "16 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10",
            "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": "SAST tool is not run on all commits -- score normalized to 0",
            "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": 0,
            "reason": "Project has not signed or included provenance with any releases.",
            "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": 8,
            "reason": "2 existing vulnerabilities detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#vulnerabilities"
          }
        ],
        "commit": "b7dd9f17f81dfdd99dcb78e01fc67614349675fc",
        "ran_at": "2026-07-28T10:25:24Z",
        "aggregate_score": 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-14T23:01:19Z",
      "oldest_open_prs": [],
      "last_merged_pr_at": "2026-07-14T22:44:00Z",
      "ci_last_conclusion": "SUCCESS",
      "oldest_open_issues": []
    }
  },
  "config": {
    "disabled_metrics": [],
    "disabled_categories": [],
    "disabled_components": {}
  },
  "source": {
    "url": "https://github.com/hostodo/odo-cli",
    "host": "github.com",
    "name": "odo-cli",
    "owner": "hostodo"
  },
  "metrics": {
    "overall": {
      "key": "overall",
      "band": "at_risk",
      "name": "Overall health",
      "note": null,
      "notes": [],
      "value": 47,
      "inputs": {
        "security": 40,
        "vitality": 75,
        "community": 16,
        "governance": 52,
        "engineering": 46
      },
      "components": []
    },
    "categories": [
      {
        "key": "vitality",
        "band": "good",
        "name": "Vitality",
        "value": 75,
        "weight": 0.22,
        "metrics": [
          {
            "key": "development_activity",
            "band": "moderate",
            "name": "Development activity",
            "note": null,
            "notes": [],
            "value": 65,
            "inputs": {
              "commits_last_year": 79,
              "human_commit_share": 1,
              "days_since_last_push": 13,
              "active_weeks_last_year": 13
            },
            "components": [
              {
                "key": "push_recency",
                "name": "Push recency",
                "detail": "last push 13 days ago",
                "points": 28.8,
                "status": "partial",
                "details": [
                  {
                    "code": "push_recency",
                    "params": {
                      "days": 13
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_cadence",
                "name": "Commit cadence",
                "detail": "13/52 weeks with commits",
                "points": 9,
                "status": "partial",
                "details": [
                  {
                    "code": "commit_cadence_weeks",
                    "params": {
                      "weeks": 13
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_volume",
                "name": "Commit volume",
                "detail": "79 commits in the last year",
                "points": 17.1,
                "status": "partial",
                "details": [
                  {
                    "code": "commits_last_year",
                    "params": {
                      "count": 79
                    }
                  }
                ],
                "max_points": 18
              },
              {
                "key": "openssf_scorecard_maintained",
                "name": "OpenSSF Scorecard: Maintained",
                "detail": "16 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "release_discipline",
            "band": "excellent",
            "name": "Release discipline",
            "note": null,
            "notes": [],
            "value": 90,
            "inputs": {
              "releases_count": 22,
              "latest_release_tag": "v2.2.0",
              "releases_from_tags": false,
              "days_since_latest_release": 13,
              "mean_days_between_releases": 11.3
            },
            "components": [
              {
                "key": "ships_releases",
                "name": "Ships releases",
                "detail": "22 releases published",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "releases_published",
                    "params": {
                      "count": 22
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "release_recency",
                "name": "Release recency",
                "detail": "latest release 13 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "release_recency",
                    "params": {
                      "days": 13
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "release_cadence",
                "name": "Release cadence",
                "detail": "a release every ~11.3 days",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "release_cadence",
                    "params": {
                      "gap": 11.3
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "openssf_scorecard_signed_releases",
                "name": "OpenSSF Scorecard: Signed-Releases",
                "detail": "Project has not signed or included provenance with any releases.",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "abandonment",
            "band": "excellent",
            "name": "Abandonment",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "cap": null,
              "state": "maintained",
              "guards": [],
              "signals": [],
              "red_flag": false,
              "multiplier_pct": 100,
              "declared_reason": null,
              "unverified_reason": null,
              "unanswered_open_prs": null,
              "unanswered_open_issues": null,
              "days_since_last_merged_pr": null,
              "days_since_last_human_commit": 13,
              "days_since_last_human_commit_is_floor": false
            },
            "components": [
              {
                "key": "project_is_still_maintained",
                "name": "Project is still maintained",
                "detail": "last human commit 13 days ago",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "abandonment_maintained",
                    "params": {
                      "days": 13
                    }
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "description": "Is the project alive — is code being written and are releases shipping?"
      },
      {
        "key": "community",
        "band": "critical",
        "name": "Community & Adoption",
        "value": 16,
        "weight": 0.18,
        "metrics": [
          {
            "key": "popularity",
            "band": "critical",
            "name": "Popularity & adoption",
            "note": null,
            "notes": [],
            "value": 8,
            "inputs": {
              "forks": 0,
              "stars": 4,
              "watchers": 0,
              "growth_state": "unverified",
              "growth_factor_pct": 100,
              "growth_unverified_reason": "no_history"
            },
            "components": [
              {
                "key": "stars",
                "name": "Stars",
                "detail": "4 stars",
                "points": 7.7,
                "status": "partial",
                "details": [
                  {
                    "code": "stars",
                    "params": {
                      "count": 4
                    }
                  }
                ],
                "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
              }
            ]
          }
        ],
        "description": "Does the project have users, downloads, attention, and a welcoming setup for contributors?"
      },
      {
        "key": "governance",
        "band": "moderate",
        "name": "Sustainability & Governance",
        "value": 52,
        "weight": 0.24,
        "metrics": [
          {
            "key": "maintainer_resilience",
            "band": "critical",
            "name": "Maintainer resilience (bus factor)",
            "note": null,
            "notes": [],
            "value": 16,
            "inputs": {
              "bus_factor": 1,
              "contributors_sampled": 2,
              "top_contributor_share": 0.962
            },
            "components": [
              {
                "key": "bus_factor",
                "name": "Bus factor",
                "detail": "1 contributor(s) cover half of all commits",
                "points": 9,
                "status": "partial",
                "details": [
                  {
                    "code": "bus_factor",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "max_points": 54
              },
              {
                "key": "commit_distribution",
                "name": "Commit distribution",
                "detail": "top contributor authored 96% of commits",
                "points": 0.9,
                "status": "partial",
                "details": [
                  {
                    "code": "top_contributor_share",
                    "params": {
                      "share": 96
                    }
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributor_breadth",
                "name": "Contributor breadth",
                "detail": "2 contributors",
                "points": 2.7,
                "status": "partial",
                "details": [
                  {
                    "code": "contributors_sampled",
                    "params": {
                      "count": 2
                    }
                  }
                ],
                "max_points": 13.5
              },
              {
                "key": "openssf_scorecard_contributors",
                "name": "OpenSSF Scorecard: Contributors",
                "detail": "project has 1 contributing companies or organizations -- score normalized to 3",
                "points": 3,
                "status": "partial",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "responsiveness",
            "band": "moderate",
            "name": "Issue & PR responsiveness",
            "note": "Excluded from scoring (no data or not applicable): Issue resolution. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "issue_resolution"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 60,
            "inputs": {
              "merged_prs": 12,
              "open_issues": 0,
              "closed_issues": 0,
              "issue_closed_ratio": null,
              "closed_unmerged_prs": 3
            },
            "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": "12/15 decided PRs merged",
                "points": 30.6,
                "status": "partial",
                "details": [
                  {
                    "code": "decided_prs_merged",
                    "params": {
                      "merged": 12,
                      "decided": 15
                    }
                  }
                ],
                "max_points": 38.25
              },
              {
                "key": "openssf_scorecard_code_review",
                "name": "OpenSSF Scorecard: Code-Review",
                "detail": "Found 3/25 approved changesets -- score normalized to 1",
                "points": 1.5,
                "status": "partial",
                "details": [],
                "max_points": 15
              }
            ]
          },
          {
            "key": "stewardship",
            "band": "moderate",
            "name": "Ownership & stewardship",
            "note": null,
            "notes": [],
            "value": 50,
            "inputs": {
              "followers": 2,
              "owner_type": "Organization",
              "is_verified": null,
              "owner_login": "hostodo",
              "public_repos": 6,
              "account_age_days": 1900
            },
            "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": "2 followers of hostodo",
                "points": 3.4,
                "status": "partial",
                "details": [
                  {
                    "code": "owner_followers",
                    "params": {
                      "count": 2,
                      "login": "hostodo"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "track_record",
                "name": "Track record",
                "detail": "6 public repos, account ~5 yr old",
                "points": 16.6,
                "status": "partial",
                "details": [
                  {
                    "code": "public_repos",
                    "params": {
                      "count": 6
                    }
                  },
                  {
                    "code": "account_age_years",
                    "params": {
                      "years": 5
                    }
                  }
                ],
                "max_points": 25
              }
            ]
          },
          {
            "key": "package_maintenance",
            "band": "excellent",
            "name": "Package maintenance",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "packages": [
                "github.com/hostodo/odo-cli/v2"
              ],
              "ecosystems": "go",
              "any_deprecated": false,
              "min_days_since_publish": 13
            },
            "components": [
              {
                "key": "published_resolvable",
                "name": "Published & resolvable",
                "detail": "1 package(s) on go",
                "points": 25,
                "status": "met",
                "details": [
                  {
                    "code": "packages_published",
                    "params": {
                      "count": 1,
                      "ecosystems": "go"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "publish_recency",
                "name": "Publish recency",
                "detail": "latest publish 13 days ago",
                "points": 35,
                "status": "met",
                "details": [
                  {
                    "code": "publish_recency",
                    "params": {
                      "days": 13
                    }
                  }
                ],
                "max_points": 35
              },
              {
                "key": "version_history",
                "name": "Version history",
                "detail": "10 published versions",
                "points": 20,
                "status": "met",
                "details": [
                  {
                    "code": "published_versions",
                    "params": {
                      "count": 10
                    }
                  }
                ],
                "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": "at_risk",
        "name": "Engineering Quality",
        "value": 46,
        "weight": 0.2,
        "metrics": [
          {
            "key": "engineering_practices",
            "band": "moderate",
            "name": "Engineering practices",
            "note": null,
            "notes": [],
            "value": 50,
            "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": "3 workflow(s)",
                "points": 24,
                "status": "met",
                "details": [
                  {
                    "code": "ci_workflows",
                    "params": {
                      "count": 3
                    }
                  }
                ],
                "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": "1 out of 8 merged PRs checked by a CI test -- score normalized to 1",
                "points": 2,
                "status": "partial",
                "details": [],
                "max_points": 20
              }
            ]
          },
          {
            "key": "documentation",
            "band": "at_risk",
            "name": "Documentation",
            "note": null,
            "notes": [],
            "value": 40,
            "inputs": {
              "topics": [],
              "has_wiki": true,
              "homepage": null,
              "has_readme": true,
              "has_docs_dir": false,
              "has_description": false
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 30,
                "status": "met",
                "details": [],
                "max_points": 30
              },
              {
                "key": "documentation_directory",
                "name": "Documentation directory",
                "detail": null,
                "points": 0,
                "status": "missed",
                "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": 0,
                "status": "missed",
                "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": "at_risk",
        "name": "Security",
        "value": 40,
        "weight": 0.16,
        "metrics": [
          {
            "key": "security_posture",
            "band": "at_risk",
            "name": "Security posture",
            "note": null,
            "notes": [],
            "value": 40,
            "inputs": {
              "source": "openssf_scorecard",
              "checks_evaluated": 18,
              "scorecard_version": "v5.5.0",
              "checks_inconclusive": 0,
              "scorecard_aggregate": 4
            },
            "components": [
              {
                "key": "binary_artifacts",
                "name": "Binary-Artifacts",
                "detail": "binaries present in source code",
                "points": 6.8,
                "status": "partial",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "branch_protection",
                "name": "Branch-Protection",
                "detail": "branch protection is not maximal on development and all release branches",
                "points": 4.5,
                "status": "partial",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "ci_tests",
                "name": "CI-Tests",
                "detail": "1 out of 8 merged PRs checked by a CI test -- score normalized to 1",
                "points": 0.2,
                "status": "partial",
                "details": [],
                "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 3/25 approved changesets -- score normalized to 1",
                "points": 0.8,
                "status": "partial",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "contributors",
                "name": "Contributors",
                "detail": "project has 1 contributing companies or organizations -- score normalized to 3",
                "points": 0.8,
                "status": "partial",
                "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": "16 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10",
                "points": 7.5,
                "status": "met",
                "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": "SAST tool is not run on all commits -- score normalized to 0",
                "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": "Project has not signed or included provenance with any releases.",
                "points": 0,
                "status": "missed",
                "details": [],
                "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": "2 existing vulnerabilities detected",
                "points": 6,
                "status": "partial",
                "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": 2
            },
            "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": "good",
        "name": "AI Readiness",
        "value": 81,
        "weight": 0,
        "metrics": [
          {
            "key": "ai_agent_context",
            "band": "excellent",
            "name": "Agent context & guidance",
            "note": null,
            "notes": [],
            "value": 85,
            "inputs": {
              "has_llms_txt": false,
              "legible_history_share": 0.975,
              "agent_instruction_files": [
                "CLAUDE.md"
              ],
              "agent_instruction_max_bytes": 4142
            },
            "components": [
              {
                "key": "agent_instructions",
                "name": "Agent instructions",
                "detail": "CLAUDE.md",
                "points": 45,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "CLAUDE.md"
                    }
                  }
                ],
                "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": "77 of 79 human commits state their intent (structured subject or explanatory body)",
                "points": 40,
                "status": "met",
                "details": [
                  {
                    "code": "legible_history",
                    "params": {
                      "legible": 77,
                      "sampled": 79
                    }
                  }
                ],
                "max_points": 40
              }
            ]
          },
          {
            "key": "ai_verify_loop",
            "band": "good",
            "name": "Verify loop (build / test / typecheck)",
            "note": null,
            "notes": [],
            "value": 71,
            "inputs": {
              "has_nix": false,
              "has_tests": true,
              "lockfiles": [
                "go.sum"
              ],
              "has_dockerfile": false,
              "typed_language": true,
              "bootstrap_files": [
                "Makefile"
              ],
              "has_devcontainer": false,
              "has_linter_config": false,
              "typecheck_configs": [],
              "agent_commit_share": 0.291,
              "toolchain_manifests": [
                "go.mod"
              ],
              "dependency_bot_commit_share": 0
            },
            "components": [
              {
                "key": "one_command_bootstrap",
                "name": "One-command bootstrap",
                "detail": "Makefile",
                "points": 18,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "Makefile"
                    }
                  }
                ],
                "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": "Go (statically typed)",
                "points": 11,
                "status": "met",
                "details": [
                  {
                    "code": "statically_typed_language",
                    "params": {
                      "language": "Go"
                    }
                  }
                ],
                "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": "23 of the last 79 commits agent-authored or agent-credited",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "agent_authored_commits",
                    "params": {
                      "count": 23,
                      "sampled": 79
                    }
                  }
                ],
                "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": 100,
            "inputs": {
              "primary_language": "Go",
              "largest_source_bytes": 25017,
              "source_files_sampled": 47,
              "oversized_source_files": 0
            },
            "components": [
              {
                "key": "type_checkable_code",
                "name": "Type-checkable code",
                "detail": "Go (statically typed)",
                "points": 45,
                "status": "met",
                "details": [
                  {
                    "code": "statically_typed_language",
                    "params": {
                      "language": "Go"
                    }
                  }
                ],
                "max_points": 45
              },
              {
                "key": "manageable_file_sizes",
                "name": "Manageable file sizes",
                "detail": "0/47 source files over 60KB",
                "points": 55,
                "status": "met",
                "details": [
                  {
                    "code": "oversized_source_files",
                    "params": {
                      "kb": 60,
                      "sampled": 47,
                      "oversized": 0
                    }
                  }
                ],
                "max_points": 55
              }
            ]
          }
        ],
        "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": [
    "Star history unavailable: GitHub GraphQL error: Resource not accessible by personal access token",
    "GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository"
  ],
  "report_type": "repository",
  "generated_at": "2026-07-28T10:25:36.558816Z",
  "schema_version": "0.27.0",
  "badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/h/hostodo/odo-cli.svg",
  "full_name": "hostodo/odo-cli",
  "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 agregadasGo.