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

MotherofallVPNs / moav-client

MoaV client — multi-protocol proxy with load balancing and web dashboard

Go · TypeScript · ShellMIT★ 6 estrellas⑂ 1 forkdesde jun 2026Ver en GitHub ↗

MotherofallVPNs/moav-client tiene un índice de salud de 50 sobre 100, lo que lo sitúa en la banda Moderado. Su puntuación más alta es AI Readiness (79/100) y la más baja, Security (29/100). Se actualizó por última vez hace 4 días. Una sola persona concentra la mayor parte del trabajo reciente.

50
global / 100
Moderado

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

50
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

2 seguidores3 repositorios públicosdesde jun 2026

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

Métricas por categoría

Vitalidad

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

76Bueno · 22% del índice global
Cómo se puntúa
36/36Recencia de push — último push hace 4 días
5.5/36Cadencia de commits — 8/52 semanas con commits
18/18Volumen de commits — 127 commits en el último año
0/10OpenSSF Scorecard: Maintained — project was created within the last 90 days. Please review its contents carefully
Datos de entrada utilizados
commits_last_year127
human_commit_share0,93
days_since_last_push4
active_weeks_last_year8
Cómo se puntúa
27/27Publica versiones — 4 versiones publicadas
36/36Recencia de las versiones — última versión hace 11 días
27/27Cadencia de publicación — una versión cada ~12,7 días
0/10OpenSSF Scorecard: Signed-Releases — sin datos
Datos de entrada utilizados
releases_count4
latest_release_tagv1.3.2
releases_from_tagsno
days_since_latest_release11
mean_days_between_releases12,7
Excluidos de la puntuación (sin datos o no aplicable): OpenSSF Scorecard: Signed-Releases. Los pesos restantes se han renormalizado.

Comunidad y Adopción

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

29Crítico · 18% del índice global
Cómo se puntúa
11.3/60Estrellas — 6 estrellas
0/25Forks — 1 forks
0/15Observadores — 1 observadores
Datos de entrada utilizados
forks1
stars6
watchers1
growth_stateunverified
growth_factor_pct100
growth_unverified_reasonno_history
Cómo se puntúa
22.5/22.5README
22.5/22.5Licencia — licencia reconocida (MIT)
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_license
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?

43En riesgo · 24% del índice global
Cómo se puntúa
9/54Factor bus — la mitad de los commits recae en 1 contribuyente(s)
9.2/22.5Distribución de commits — el principal contribuyente firma el 59% de los commits
2.7/13.5Amplitud de contribuyentes — 2 contribuyentes
10/10OpenSSF Scorecard: Contributors — project has 12 contributing companies or organizations
Datos de entrada utilizados
bus_factor1
contributors_sampled2
top_contributor_share0,592
Cómo se puntúa
23.4/46.8Resolución de issues — 50% de issues cerradas
38.2/38.3Aceptación de PR — 12/12 PR decididos fusionados
0/15OpenSSF Scorecard: Code-Review — Found 1/13 approved changesets -- score normalized to 0
Datos de entrada utilizados
merged_prs12
open_issues2
closed_issues2
issue_closed_ratio0,5
closed_unmerged_prs0
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 MotherofallVPNs
4.7/25Trayectoria — 3 repos públicos, cuenta de ~0 años
Datos de entrada utilizados
followers2
owner_typeOrganization
is_verified
owner_loginMotherofallVPNs
public_repos3
account_age_days52

Calidad de Ingeniería

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

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

Documentación

65Moderado
Cómo se puntúa
30/30README
25/25Directorio de documentación
0/15Sitio de documentación / página del proyecto
10/10Descripción del repositorio
0/10Topics
0/10Wiki
Datos de entrada utilizados
topics
has_wikino
homepage
has_readme
has_docs_dir
has_description

Seguridad

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

29Crítico · 16% del índice global
Cómo se puntúa
7.5/7.5Binary-Artifacts — no binaries found in the repo
0/7.5Branch-Protection — branch protection not enabled on development/release branches
2.5/2.5CI-Tests — 8 out of 8 merged PRs checked by a CI test -- score normalized to 10
0/2.5CII-Best-Practices — no effort to earn an OpenSSF best practices badge detected
0/7.5Code-Review — Found 1/13 approved changesets -- score normalized to 0
2.5/2.5Contributors — project has 12 contributing companies or organizations
10/10Dangerous-Workflow — no dangerous workflow patterns detected
0/7.5Dependency-Update-Tool — no update tool detected
0/5Fuzzing — project is not fuzzed
2.5/2.5Licencia — license file detected
0/7.5Maintained — project was created within the last 90 days. Please review its contents carefully
0/5Packaging — sin datos
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 — sin datos
0/7.5Token-Permissions — detected GitHub workflow tokens with excessive permissions
1.5/7.5Vulnerabilities — 8 existing vulnerabilities detected
Datos de entrada utilizados
sourceopenssf_scorecard
checks_evaluated16
scorecard_versionv5.5.0
checks_inconclusive2
scorecard_aggregate2,9
Excluidos de la puntuación (sin datos o no aplicable): packaging, signed_releases. Los pesos restantes se han renormalizado.

Preparación para IA

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

79Bueno · 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 — 91 de 93 commits humanos declaran su intención (asunto estructurado o cuerpo explicativo)
Datos de entrada utilizados
has_llms_txtno
legible_history_share0,978
agent_instruction_filesCLAUDE.md
agent_instruction_max_bytes18.574
Cómo se puntúa
12.6/18Arranque con un solo comando — proxy-core/go.mod (convención del toolchain, sin ejecutor de tareas)
22/22Pruebas automatizadas
0/11Configuración de lint / formato
11/11Verificación estática de tipos — web-ui/tsconfig.json
10/10Entorno reproducible — Dockerfile, lockfile
10/10Práctica demostrada con agentes — 73 de los últimos 100 commits con autoría o crédito de agente
0/8Mantenimiento automatizado — no se observan actualizaciones automáticas de dependencias
0/10OpenSSF Scorecard: Pinned-Dependencies — dependency not pinned by hash detected -- score normalized to 0
Datos de entrada utilizados
has_nixno
has_tests
lockfilesgo.sum, package-lock.json
has_dockerfile
typed_language
bootstrap_files
has_devcontainerno
has_linter_configno
typecheck_configsweb-ui/tsconfig.json
agent_commit_share0,73
toolchain_manifestsproxy-core/go.mod
dependency_bot_commit_share0
Cómo se puntúa
45/45Código verificable por tipos — Go (tipado estático)
54.3/55Tamaños de archivo manejables — 1/81 archivos fuente de más de 60 KB
Datos de entrada utilizados
primary_languageGo
largest_source_bytes62.396
source_files_sampled81
oversized_source_files1

Datos clave

6estrellas de GitHub
2contribuidores
127commits en los últimos 12 meses
4días desde el último push
4versiones publicadas
1factor bus
2issues abiertas
Go, npmecosistemas de paquetes

Advertencias de recopilación de datos

  • Star history unavailable: GitHub GraphQL error: Resource not accessible by personal access token
  • Could not fetch go package 'github.com/ibeezhan/moav-client/proxy-core' from its registry
  • GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository

Más detalle

OpenSSF Scorecard 2.9 / 10
2.9agregado

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-25 00:36 UTC

10Binary-Artifactsno binaries found in the repo
0Branch-Protectionbranch protection not enabled on development/release branches
10CI-Tests8 out of 8 merged PRs checked by a CI test -- score normalized to 10
0CII-Best-Practicesno effort to earn an OpenSSF best practices badge detected
0Code-ReviewFound 1/13 approved changesets -- score normalized to 0
10Contributorsproject has 12 contributing companies or organizations
10Dangerous-Workflowno dangerous workflow patterns detected
0Dependency-Update-Toolno update tool detected
0Fuzzingproject is not fuzzed
10Licenselicense file detected
0Maintainedproject was created within the last 90 days. Please review its contents carefully
n/dPackagingpackaging workflow not 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
n/dSigned-Releasesno releases found
0Token-Permissionsdetected GitHub workflow tokens with excessive permissions
2Vulnerabilities8 existing vulnerabilities detected
Dependencias directas 4
RegistroPaqueteRestricción de versiónManifiesto
Gogithub.com/armon/go-socks5v0.0.0-20160902184237-e75332964ef5proxy-core/go.mod
Gogopkg.in/yaml.v3v3.0.1proxy-core/go.mod
npmreact^18.3.1web-ui/package.json
npmreact-dom^18.3.1web-ui/package.json
Todas las dependencias no recopilado

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

Informe JSON sin procesar legible por máquina
{
  "data": {
    "repo": {
      "topics": [],
      "is_fork": false,
      "size_kb": 3303,
      "has_wiki": false,
      "homepage": null,
      "languages": {
        "Go": 347119,
        "HTML": 423,
        "Shell": 73024,
        "Dockerfile": 13944,
        "TypeScript": 185449
      },
      "pushed_at": "2026-07-20T07:27:36Z",
      "created_at": "2026-06-02T21:28:10Z",
      "owner_type": "Organization",
      "updated_at": "2026-07-20T07:27:46Z",
      "description": "MoaV client — multi-protocol proxy with load balancing and web dashboard",
      "is_archived": false,
      "is_disabled": false,
      "license_spdx": "MIT",
      "default_branch": "main",
      "license_spdx_raw": "MIT",
      "primary_language": "Go",
      "significant_languages": [
        "Go",
        "TypeScript",
        "Shell"
      ]
    },
    "owner": {
      "blog": "https://moav.sh",
      "name": "MoaV - Mother of all VPNs",
      "type": "Organization",
      "login": "MotherofallVPNs",
      "company": null,
      "location": null,
      "followers": 2,
      "avatar_url": "https://avatars.githubusercontent.com/u/290194482?v=4",
      "created_at": "2026-06-03T00:07:19Z",
      "is_verified": null,
      "public_repos": 3,
      "account_age_days": 52
    },
    "license": {
      "state": "standard",
      "spdx_id": "MIT",
      "raw_spdx": "MIT",
      "file_present": true,
      "scorecard_found": true,
      "profile_has_license": true
    },
    "activity": {
      "releases": [
        {
          "tag": "v1.3.2",
          "kind": "patch",
          "published_at": "2026-07-13T21:18:20Z"
        },
        {
          "tag": "v1.3.1",
          "kind": "patch",
          "published_at": "2026-06-09T14:04:53Z"
        },
        {
          "tag": "v1.3.0",
          "kind": "minor",
          "published_at": "2026-06-08T23:20:44Z"
        },
        {
          "tag": "v1.0.0",
          "kind": "major",
          "published_at": "2026-06-05T17:10:58Z"
        }
      ],
      "recent_commits": [
        {
          "oid": "0c24d7c076624f60a176dbbbb55c86c27ab20251",
          "body": null,
          "is_bot": true,
          "headline": "chore(geoip): refresh CIDR lists [skip ci]",
          "author_name": "github-actions[bot]",
          "author_login": "github-actions[bot]",
          "committed_at": "2026-07-20T07:27:35Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f8fa6273a23889d9f00894289c19e90bc7e7a583",
          "body": "feat: publish install.sh as release asset + moav.sh/client-install.sh",
          "is_bot": false,
          "headline": "Merge pull request #16 from MotherofallVPNs/feat/client-install-url",
          "author_name": "Shayan Eskandari",
          "author_login": "shayanb",
          "committed_at": "2026-07-17T17:27:07Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b666483ed9bfb4535b60c1737d57a5deeac2f1fa",
          "body": "…ll.sh\n\nAdd a publish-install workflow that uploads install.sh as the `client-install.sh`\nrelease asset on each release, so moav.sh can serve the latest installer\n(reachable in censored networks) — mirroring the MoaV server's install.sh.\nPoint the README (EN + FA), docs/INSTALL.md, and the installer\n[…]\nown usage\nbanner at the new moav.sh/client-install.sh URL.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01NzWWMGR3wAkaa9HHAQRtRL",
          "is_bot": false,
          "headline": "feat: publish install.sh as a release asset; use moav.sh/client-insta…",
          "author_name": "Beezhan",
          "author_login": "ibeezhan",
          "committed_at": "2026-07-17T17:22:01Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "68268173c2db580d9d2cb61067a6f24cfb5640c0",
          "body": "…the grid\n\nPromote dashboard.gif to the top hero; the static Endpoints screenshot now\nopens the Web dashboard section above the Analytics/Plugins/Configs/Settings grid.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01NzWWMGR3wAkaa9HHAQRtRL",
          "is_bot": false,
          "headline": "docs: lead README with the walkthrough GIF, move Endpoints shot into …",
          "author_name": "Beezhan",
          "author_login": "ibeezhan",
          "committed_at": "2026-07-17T16:16:45Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "6fb209ae8c1aa7213dd7e1687753a03e6dba0eb2",
          "body": "Wire the Endpoints hero, walkthrough GIF, and Analytics/Plugins/Configs/\nSettings tab screenshots into README.md and README-fa.md. All server IPs,\ndomains, bundle names, and personal egress IP are masked in the captures.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01NzWWMGR3wAkaa9HHAQRtRL",
          "is_bot": false,
          "headline": "docs: add dashboard screenshots + walkthrough GIF to README",
          "author_name": "Beezhan",
          "author_login": "ibeezhan",
          "committed_at": "2026-07-17T15:53:45Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "fc74095bd24cc0c86e7fe2caa5118fa38b1d8b7f",
          "body": "…ifier\n\nci: Telegram release/issue notifier (mirrors moav server)",
          "is_bot": false,
          "headline": "Merge pull request #15 from MotherofallVPNs/feat/telegram-release-not…",
          "author_name": "Shayan Eskandari",
          "author_login": "shayanb",
          "committed_at": "2026-07-15T16:11:29Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "4abf49f8f67d5042546b7e10975955641d3ac28f",
          "body": "Auto-posts to the shared MoaV Telegram channel on:\n- release published → title (prefixed \"moav-client\") + notes excerpt + links\n- issue labeled `announce` → title + link\n- workflow_dispatch → test message, or a real notification for a past\n  release via the `release_tag` input\n\nMirror of Motherofall\n[…]\ns TELEGRAM_BOT_TOKEN\n+ TELEGRAM_CHAT_ID; sends skip cleanly when unset.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_012BWuTaD7kxGQksBLFHrUEp",
          "is_bot": false,
          "headline": "ci: Telegram release/issue notifier (mirrors moav server)",
          "author_name": "Shayan Eskandari",
          "author_login": "shayanb",
          "committed_at": "2026-07-15T16:05:09Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "b7f67e1aadd1f20d0eb8ee516330fc4f94104ea0",
          "body": "…back\n\nfix(e2e): synthesize subscription.txt for text-only/older bundles",
          "is_bot": false,
          "headline": "Merge pull request #14 from MotherofallVPNs/fix/e2e-subscription-fall…",
          "author_name": "Shayan Eskandari",
          "author_login": "shayanb",
          "committed_at": "2026-07-14T00:51:38Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "5b986cb38bfe8ed93e8cbbb6e84ae60f32f147be",
          "body": null,
          "is_bot": false,
          "headline": "ci(e2e): reference the renamed `moav user base64` in the bundle_b64 help",
          "author_name": "Shayan Eskandari",
          "author_login": "shayanb",
          "committed_at": "2026-07-14T00:48:58Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f30ba06aa6383c177c7a3411ce8a3bdbe0d491cf",
          "body": "A text-only or older MoaV bundle can lack subscription.txt (it's normally\nwritten alongside the rendered README). Instead of failing, build it from the\nbundle's share-link files (base64 of the joined vless/trojan/ss/hysteria2/anytls\nURIs — MoaV's own format), so any server bundle works with the client e2e.",
          "is_bot": false,
          "headline": "fix(e2e): synthesize subscription.txt when a bundle omits it",
          "author_name": "Shayan Eskandari",
          "author_login": "shayanb",
          "committed_at": "2026-07-14T00:48:32Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "bf4bd054c368a95a014a5e9daf8757f6a665e694",
          "body": "…d-masking\n\nci(e2e): dispatch config inputs + full logs + IP/domain masking",
          "is_bot": false,
          "headline": "Merge pull request #13 from MotherofallVPNs/ci/e2e-dispatch-config-an…",
          "author_name": "Shayan Eskandari",
          "author_login": "shayanb",
          "committed_at": "2026-07-14T00:23:37Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a8dc62efbd043a3ec42101f5b247934dd1b3c3c2",
          "body": "- workflow_dispatch inputs bundle_b64 / sub_url / exit_ip override the standing\n  secrets, so you can point the client e2e at any deployed MoaV server ad-hoc\n  (e.g. paste the base64 from `moav test generate <user>`). On push/release the\n  inputs are empty and the secrets are used.\n- full_logs input\n[…]\nthe assertion. Best-effort redaction of the known exit IP in artifacts.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_012BWuTaD7kxGQksBLFHrUEp",
          "is_bot": false,
          "headline": "ci(e2e): dispatch config inputs + full-log snapshots + IP/domain masking",
          "author_name": "Shayan Eskandari",
          "author_login": "shayanb",
          "committed_at": "2026-07-14T00:11:54Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "9ce4eaf181497476def5bb18ca50c42e88ea1759",
          "body": "ci(e2e): run e2e on every push to main",
          "is_bot": false,
          "headline": "Merge pull request #12 from MotherofallVPNs/ci/e2e-on-push-main",
          "author_name": "Shayan Eskandari",
          "author_login": "shayanb",
          "committed_at": "2026-07-13T21:40:13Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f066728b644981f7b5c715d91b44f2fc7617e0f6",
          "body": "Adds `push: branches: [main]` alongside workflow_dispatch and release, so\neach merge to main validates the full client round-trip on the\nself-hosted runner (warm cache makes it ~30s). Manual dispatch and\non-release triggers are unchanged.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "ci(e2e): run the live e2e on every push to main (+ keep manual/release)",
          "author_name": "Shayan Eskandari",
          "author_login": "shayanb",
          "committed_at": "2026-07-13T21:35:49Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "a646f2320c3976738cc4d61d9571da4e9a851ad8",
          "body": "fix(api): build on Windows — platform-split IP_TTL setsockopt (#7)",
          "is_bot": false,
          "headline": "Merge pull request #11 from MotherofallVPNs/fix/windows-build-issue-7",
          "author_name": "Shayan Eskandari",
          "author_login": "shayanb",
          "committed_at": "2026-07-13T21:30:07Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b25cfee2093ca7482becffda5258ce5443d4ab5b",
          "body": "makeTTLControl (the /api/diag by-hand traceroute) called\nsyscall.SetsockoptInt(int(fd), ...), but a socket fd is int on Unix and\nsyscall.Handle on Windows, so `go build` failed on Windows:\n\"cannot use int(fd) ... as syscall.Handle value\". Move the setter into\napi/ttl_unix.go + api/ttl_windows.go behind build tags. Verified builds\non windows/linux/darwin; api tests pass. CI now cross-compiles for\nwindows+darwin so this class is caught.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(api): build on Windows — platform-split IP_TTL setsockopt (#7)",
          "author_name": "Shayan Eskandari",
          "author_login": "shayanb",
          "committed_at": "2026-07-13T21:27:40Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "f58fde720cd639e9e270aa417cbc37e395bc144f",
          "body": "release: v1.3.2",
          "is_bot": false,
          "headline": "Merge pull request #10 from MotherofallVPNs/release/1.3.2",
          "author_name": "Shayan Eskandari",
          "author_login": "shayanb",
          "committed_at": "2026-07-13T21:17:56Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f8ff8cc7c94a9575567fdfd69a4dc29138be1533",
          "body": "Bump VERSION / web-ui package.json / proxy-core cli.go fallback to 1.3.2\nand cut the [1.3.2] changelog. Ships the full CI/testing suite (Go +\nweb-ui unit tests, parity guard, coverage/golangci-lint/compose CI, live\ne2e), the docs/PROTOCOL-PARITY.md audit, and the Slipstream dead-stub\nremoval. No user-facing feature change — v2 will jump to 2.0.0.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "release: v1.3.2 — testing suite + parity audit",
          "author_name": "Shayan Eskandari",
          "author_login": "shayanb",
          "committed_at": "2026-07-13T21:16:53Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "3e4a3df3b2d3168444309f42cabba7c0f2b19bd0",
          "body": "test+ci: full testing suite + protocol parity audit (v2 hardening)",
          "is_bot": false,
          "headline": "Merge pull request #9 from MotherofallVPNs/test/full-testing-suite",
          "author_name": "Shayan Eskandari",
          "author_login": "shayanb",
          "committed_at": "2026-07-13T21:04:40Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "6f4719f205254b08db59dbf84e4ac1bcfde04b3e",
          "body": null,
          "is_bot": true,
          "headline": "chore(geoip): refresh CIDR lists [skip ci]",
          "author_name": "github-actions[bot]",
          "author_login": "github-actions[bot]",
          "committed_at": "2026-07-13T07:35:44Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "59e6039d8a4962697f6cecd4c4829d6c363b793c",
          "body": "# Conflicts:\n#\ttests/e2e-client.sh",
          "is_bot": false,
          "headline": "Merge remote-tracking branch 'origin/main' into test/full-testing-suite",
          "author_name": "Shayan Eskandari",
          "author_login": "shayanb",
          "committed_at": "2026-07-12T20:38:13Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b4dbdc8c0d73f4574dc4b4d8aa31e7c3307eff49",
          "body": "Run 6 exited via the runner's own IP — the balancer's involuntary direct\nfallback leaked when the picked endpoint failed, making the exit-IP\nassertion meaningless. Set block_direct=true so a fetch through :1080\negresses from the server or fails cleanly (no leak), and retry the\nexit-IP fetch (~75s) so the balancer can fail over to a working endpoint\nwhile probes settle.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(e2e): tunnel-only exit-IP check (block_direct) + retry",
          "author_name": "Shayan Eskandari",
          "author_login": "shayanb",
          "committed_at": "2026-07-12T20:18:35Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "053e1d12161df629a7b7935b20dd0435cf19d6e7",
          "body": "/api/endpoints returns {\"endpoints\":[...]} (a wrapper object) with\ncapitalized Go field names (.Status/.Protocol/.LatencyMs/.ID), not a\nbare array of lowercase-tagged objects. My jq read `length` (=1 for the\nobject) and `.[].status` (never matched) — so a run with 6 OK endpoints\nlooked like \"1 parse\n[…]\nds.\n\nThe artifact from run 5 confirmed the client actually connects: Reality,\nCDN, Trojan, Shadowsocks-2022, Hysteria2, WireGuard all validated.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(e2e): parse the real /api/endpoints shape",
          "author_name": "Shayan Eskandari",
          "author_login": "shayanb",
          "committed_at": "2026-07-12T20:14:46Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "c212b1c1c81018f177d2c276a5cae0738fa17990",
          "body": "python3 -m zipfile / different zip tooling can nest the bundle under a\ntop-level dir, so the flat data/e2e-bundle/subscription.txt path missed.\nfind it wherever it landed and derive the bundle dir + wg confs from\nthere; dump the extracted file list if it's genuinely absent.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(e2e): find subscription.txt anywhere in the extracted bundle",
          "author_name": "Shayan Eskandari",
          "author_login": "shayanb",
          "committed_at": "2026-07-12T20:09:00Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "1440796072c3e08ec375f1aefe1c86c58413ac3f",
          "body": "The runner has no `unzip` (exit 127). Fall back to\n`python3 -m zipfile -e` (already present on the e2e box), or fail with a\nclear message if neither is available.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(e2e): portable bundle extraction (unzip or python3)",
          "author_name": "Shayan Eskandari",
          "author_login": "shayanb",
          "committed_at": "2026-07-12T20:06:52Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "2040ed3e94937bb2cc923987102207d3e8bda65b",
          "body": "Two fixes from the first live run:\n- subscription.file wants a subscription.txt (a URI list), not a bundle\n  .zip — feeding the zip parsed 1 lucky URI. Unzip the bundle and point\n  file at data/e2e-bundle/subscription.txt (+ wireguard_files for the WG\n  confs), so all the URI/WG protocols load.\n- PO\n[…]\nll\n  /api/endpoints for status==\"ok\" afterward instead of reading the probe\n  response, with a timeout and early-exit once all endpoints settle.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(e2e): unzip bundle for subscription.file + poll async probe",
          "author_name": "Shayan Eskandari",
          "author_login": "shayanb",
          "committed_at": "2026-07-12T20:05:15Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "571d6d62d684192bf729d6837e6ad757f7305505",
          "body": "docker-compose.yml declares env_file: .env (and bind-mounts ./.env), so\n`docker compose up` fails immediately (\"env file .env not found\") when\nit's absent. Seed it from .env.example in the helper, like the CI\ncompose-validate job does.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(e2e): seed .env before docker compose up",
          "author_name": "Shayan Eskandari",
          "author_login": "shayanb",
          "committed_at": "2026-07-12T19:59:36Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "6fcc997ebcbe6ce5d4d1ab5cbcbf73b22e05a398",
          "body": "workflow_dispatch only lists a workflow when it lives on the default\nbranch, so add e2e.yml (+ its tests/e2e-client.sh helper) to main to\nsurface \"Run workflow\". The full testing suite it belongs to is in\nPR #9 (branch test/full-testing-suite); dispatch selecting that ref to\nrun against the complete changes.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "ci(e2e): add the e2e workflow to the default branch",
          "author_name": "Shayan Eskandari",
          "author_login": "shayanb",
          "committed_at": "2026-07-12T19:57:13Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "1ed437b47aa80a632be87501e93e884dfa9eada3",
          "body": "A full bundle's README.html + QR PNGs exceed GitHub's ~64KB secret cap;\ndocument dropping them and re-zipping the config files only.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs(e2e): note bundles must be stripped to fit the secret limit",
          "author_name": "Shayan Eskandari",
          "author_login": "shayanb",
          "committed_at": "2026-07-12T19:54:27Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "159b405b8c695cdf1cdd0543a72dc1d356e5e0c3",
          "body": "macOS base64 (BSD) has no -w0; document `base64 -i bundle.zip | tr -d '\\n'`\nfor macOS alongside the GNU `base64 -w0` form.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs(e2e): cross-platform base64 for the bundle secret",
          "author_name": "Shayan Eskandari",
          "author_login": "shayanb",
          "committed_at": "2026-07-12T19:51:08Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "344a40f739ebafd2fc39a2baf4ade2de4cbe8c8f",
          "body": "Add the live client e2e: tests/e2e-client.sh brings the stack up against\na provided MoaV server bundle and asserts endpoints parse, /api/probe\nvalidates >=1 endpoint (tunnel + TLS), and a fetch through SOCKS5 :1080\negresses from the server's IP (not the runner's). Driven by\n.github/workflows/e2e.yml\n[…]\ner run) with\nits open questions. The e2e is opt-in / not on the PR path, so it awaits\nrunner setup to validate — same rollout as the server e2e.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "test+ci: Phase 2 — live e2e workflow + self-hosted runner doc",
          "author_name": "Shayan Eskandari",
          "author_login": "shayanb",
          "committed_at": "2026-07-12T19:36:45Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "4a78d1413f73a84fe43e759e2eccc88ef8cd06cb",
          "body": "Slipstream was declared (config toggle + manager entry + UI leftovers)\nbut had no docker-compose service, so enabling it made the balancer dial\na nonexistent slipstream:5302 host. Remove the stub across proxy-core\n(config.SidecarsConfig, sidecars manager) and web-ui (label + chart\ncolors). Go build/\n[…]\nabeled MasterDNS copy (runs the\nmasterdns binary), so a real dnstt client is separate feature work.\ndocs/PROTOCOL-PARITY.md updated accordingly.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(sidecars): remove dead Slipstream stub",
          "author_name": "Shayan Eskandari",
          "author_login": "shayanb",
          "committed_at": "2026-07-12T19:32:38Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "0a20a839e401ecfa622a7a26e28ef60ccc0bb71c",
          "body": "Go (proxy-core): unit tests for the previously-untested packages —\nbalancer (0→57%), state (0→75%), cmd (0→37%), sidecars (0→93%) — and a\nlift to the sing-box generator (46→88%). singbox/parity_test.go is a\nprotocol parity guard: it pins each protocol's outbound shape and\nasserts the Xray-only trans\n[…]\nOCOL-PARITY.md: client↔server protocol audit (13 full, 2\npartial; hard gaps wstunnel/XDNS/GooseRelay/Snowflake, Slipstream stub,\ndnstt unwired).\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "test+ci: Phase 1 — Go/web-ui unit tests, parity guard, CI hardening",
          "author_name": "Shayan Eskandari",
          "author_login": "shayanb",
          "committed_at": "2026-07-12T19:14:33Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "2d9de8ce6031b190ff5cd29e1ed228780d495634",
          "body": "chore(org): point MoaV links at MotherofallVPNs/moav",
          "is_bot": false,
          "headline": "Merge pull request #8 from MotherofallVPNs/chore/org-ref-sweep",
          "author_name": "Shayan Eskandari",
          "author_login": "shayanb",
          "committed_at": "2026-07-12T14:18:03Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "1e24c092be16801af6dadedd22278c1741f2c6b3",
          "body": "The server repo moved shayanb/MoaV -> MotherofallVPNs/moav. Update the\nreferences in README/README-fa, CLAUDE.md, docs/MOAV_BUNDLE.md, and the\nweb-ui theme comment.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore(org): point MoaV links at MotherofallVPNs/moav",
          "author_name": "Shayan Eskandari",
          "author_login": "shayanb",
          "committed_at": "2026-07-12T14:16:14Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "c72281a97d33a9f557fc02b29bf2ff673dbb6439",
          "body": "feat: AnyTLS protocol support",
          "is_bot": false,
          "headline": "Merge pull request #6 from MotherofallVPNs/feat/anytls-protocol",
          "author_name": "Shayan Eskandari",
          "author_login": "shayanb",
          "committed_at": "2026-07-11T20:49:51Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "6491322faffe767f4af41370512652e918523b07",
          "body": null,
          "is_bot": true,
          "headline": "chore(geoip): refresh CIDR lists [skip ci]",
          "author_name": "github-actions[bot]",
          "author_login": "github-actions[bot]",
          "committed_at": "2026-07-06T08:40:19Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0399e4fd7484ec38f2ee46eb5a7aaa2906459e2d",
          "body": null,
          "is_bot": true,
          "headline": "chore(geoip): refresh CIDR lists [skip ci]",
          "author_name": "github-actions[bot]",
          "author_login": "github-actions[bot]",
          "committed_at": "2026-06-29T09:06:27Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d5b446e4ffa56c691c48d097323f1875f6a7a0db",
          "body": null,
          "is_bot": true,
          "headline": "chore(geoip): refresh CIDR lists [skip ci]",
          "author_name": "github-actions[bot]",
          "author_login": "github-actions[bot]",
          "committed_at": "2026-06-22T10:14:39Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "1f38fea4d6fe55cad3f98ac7cdb856401995507d",
          "body": null,
          "is_bot": true,
          "headline": "chore(geoip): refresh CIDR lists [skip ci]",
          "author_name": "github-actions[bot]",
          "author_login": "github-actions[bot]",
          "committed_at": "2026-06-15T10:32:43Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "156927ccb441b331214539570920070de8ad2973",
          "body": "Mirror the Trojan path end-to-end for the AnyTLS protocol:\n\n- subscription parser: parse anytls:// URIs (password userinfo, host,\n  port, sni, insecure/allowInsecure flag, fragment label; bracketed IPv6)\n- sing-box generator: emit an anytls outbound with a TLS block\n  (server_name, insecure) + utls \n[…]\nsplay map\n- tests: parser round-trip (incl. IPv6 + insecure aliases), sing-box\n  outbound mapping, and moav bundle expansion coverage\n- docs: README (EN/FA), CLAUDE.md, ARCHITECTURE.md, MOAV_BUNDLE.md",
          "is_bot": false,
          "headline": "feat: AnyTLS protocol support",
          "author_name": "Beezhan",
          "author_login": "ibeezhan",
          "committed_at": "2026-06-13T16:51:03Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "99d87afac07340a97818c0d12037dd6cd79a068a",
          "body": "- moav-client api_curl(): send MOAV_DASHBOARD_USER/PASS basic-auth from .env to\n  the API, so `stats`/`probe`/`status` work once a dashboard password is set\n  (previously 401 after exposing on LAN).\n- update: restore a deleted data/.gitkeep before the local-changes guard, so a\n  tracked dir-placehol\n[…]\nng…\" line) so it renders once with the real mode instead of\n  painting loopback then reflowing to lan when the auth panels appear.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: wrapper API auth + update .gitkeep guard; settings exposure reflow",
          "author_name": "Shayan Eskandari",
          "author_login": "shayanb",
          "committed_at": "2026-06-09T14:44:40Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "b6b330bb34d0eee85c4810efefc4963d9638e8b2",
          "body": "A stray `2>/dev/null` on the `read -r -p` calls in confirm_yes (update rebuild\nprompt) and cmd_uninstall hid the question — read writes its -p prompt to\nstderr, so users saw the warning then \"cancelled\" with no visible Y/N. Dropped\nthe redirect; </dev/tty alone handles the no-TTY case.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(cli): show the uninstall/update confirm prompts",
          "author_name": "Shayan Eskandari",
          "author_login": "shayanb",
          "committed_at": "2026-06-09T14:04:26Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "7304f0cb1d5ebc1f97cf7b9e2a0c8d1f89c84fa1",
          "body": null,
          "is_bot": false,
          "headline": "Merge remote-tracking branch 'origin/dev'",
          "author_name": "Shayan Eskandari",
          "author_login": "shayanb",
          "committed_at": "2026-06-09T14:03:20Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "6b6d812405338c14fd1b3a008a7f62dadb27613c",
          "body": "…docs\n\n- Add mem_limit + cpus to every service in docker-compose.yml (matching the\n  MoaV server): 256m/1.0 for proxy-core & sing-box, 256m/0.5 for xray/tor/\n  amneziawg/trusttunnel/psiphon, 128m/0.5 for web-ui/masterdns/sni-spoof/caddy.\n  Previously unbounded (could use all host RAM).\n- Replace est\n[…]\nper-service caps;\n  footprint totals corrected (core ~276 MB disk / ~35 MB RAM, full ~970 MB /\n  ~130 MB), build-cache note ~8 GB.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(compose): per-container memory/CPU limits; exact image sizes in …",
          "author_name": "Shayan Eskandari",
          "author_login": "shayanb",
          "committed_at": "2026-06-09T13:46:09Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "1b886ece611092bc6cabced5049c9c5bcfc92d84",
          "body": "…ease notes\n\n- `moavc update` now asks `rebuild & restart now? [Y/n]` (default yes) after\n  pulling; on no it leaves the new code pulled and notes that it only takes\n  effect after a rebuild & restart. New confirm_yes helper (defaults yes when\n  there's no TTY, so non-interactive updates still rebuild).\n- .gitignore: ignore .DS_Store and local RELEASE_v*.md paste artifacts.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(cli): prompt before rebuild on update; gitignore .DS_Store / rel…",
          "author_name": "Shayan Eskandari",
          "author_login": "shayanb",
          "committed_at": "2026-06-09T13:40:27Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "d0d7a78f2f91ee18a9dbc166b52483caa323129e",
          "body": "…Tunnel msg\n\n- Add the GOPROXY=…|goproxy.cn|direct + GOSUMDB=off fallback to every\n  Go-building image (proxy-core, sni-spoof, psiphon, amneziawg; xray already\n  had it). Fixes `docker compose build` aborting on a 403 from Google's module\n  CDN under rate-limiting (e.g. some VPS IPs/regions).\n- inst\n[…]\nITECTURE.md — the sidecar builds the official upstream\n  client and only needs the bundle's client.toml (now a needs-config note).\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(build): resilient GOPROXY in all Go images; install polish; Trust…",
          "author_name": "Shayan Eskandari",
          "author_login": "shayanb",
          "committed_at": "2026-06-09T13:28:17Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "afd7e18fb5f07ab3f665bc65393dfd01266d3bc3",
          "body": "Release v1.3.1 — moavc alias, status fix, exposure-toggle restyle",
          "is_bot": false,
          "headline": "Merge pull request #5 from MotherofallVPNs/dev",
          "author_name": "Shayan Eskandari",
          "author_login": "shayanb",
          "committed_at": "2026-06-09T13:13:13Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "967129958774a6344e195379d5a8e6486a7a39ae",
          "body": "- Installer symlinks `moavc` into PATH alongside `moav-client` (and uninstall\n  removes both). `moavc` is the short official alias.\n- Docs/READMEs use `moavc` in command examples, with a note that `moav-client`\n  still works (quick-start + INSTALL).\n- Bump VERSION / cmd.Version / compose / Dockerfil\n[…]\nample / package.json\n  to 1.3.1; CHANGELOG entry covering the alias, the empty-arg compose fix, and\n  the exposure-toggle restyle.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: add `moavc` alias, bump to v1.3.1",
          "author_name": "Shayan Eskandari",
          "author_login": "shayanb",
          "committed_at": "2026-06-09T12:55:26Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "4052470a56913fcfdb5e03706c253d807a644425",
          "body": "…enabled\n\n`compose \"${args[@]:-}\" ps` expands an empty array to a single empty-string\nargument, so `docker compose \"\" ps` ran and errored. Use the\n`${args[@]+\"${args[@]}\"}` idiom, which expands to nothing when empty and the\nquoted elements otherwise. Fixes `moav-client status` (and up/down/logs/upda\n[…]\nNetwork-exposure on/off toggles as a real sliding switch\n(track + knob + label) so they clearly read as actionable, not just text.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(cli): don't pass an empty arg to docker compose when no sidecars …",
          "author_name": "Shayan Eskandari",
          "author_login": "shayanb",
          "committed_at": "2026-06-08T23:23:41Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "0a1d954f6e4edffac3e52f023e06c6bb601b3f87",
          "body": "Release v1.3.0 — installer/CLI overhaul, official Xray, version pinning, Settings redesign",
          "is_bot": false,
          "headline": "Merge pull request #3 from MotherofallVPNs/dev",
          "author_name": "Shayan Eskandari",
          "author_login": "shayanb",
          "committed_at": "2026-06-08T23:17:54Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "430fc196ae729a75d12359865a48ceca12b99ff8",
          "body": "- README / README-fa: auto-install + checklist wizard in quick-start; new CLI\n  commands (status/info/expose/update -b/uninstall); official-XTLS xray row +\n  updated footprint; Sources→Configs tab; Config tab folded into Settings;\n  clarify management-wrapper vs proxy-core binary; version-pinning no\n[…]\n sections.\n- SIDECARS / TROUBLESHOOTING: Sources→Configs; add shallow-clone branch-switch\n  recovery and uninstall/reset guidance.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs: refresh READMEs + docs for v1.3.0",
          "author_name": "Shayan Eskandari",
          "author_login": "shayanb",
          "committed_at": "2026-06-08T23:05:49Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "2fa0533132173f89f3366c5aa96383bc0dcd2dbb",
          "body": "Group the Settings page into responsive carded panels instead of one long\nscroll: strategy + probe alongside network exposure (row 1), access & URLs\nalongside SNI spoofing (row 2), then backup & restore and the collapsed\nadvanced YAML editor full-width. Single column on mobile.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(ui): two-column Settings layout to reduce overwhelm",
          "author_name": "Shayan Eskandari",
          "author_login": "shayanb",
          "committed_at": "2026-06-08T22:58:28Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "f43f9df307574d8a6695e9a1646f4c7b975f27c8",
          "body": "…u, size table, random password\n\n- update: fetch the target branch's tip explicitly and reset the local branch\n  to it (git fetch --depth=1 origin <branch>; checkout -B … FETCH_HEAD), so it\n  works on the installer's shallow single-branch clone where `fetch --all` and\n  origin/<other-branch> don't e\n[…]\nprompt now auto-generates a random one when left\n  empty and prints it (with where it's stored) instead of leaving the panel open.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(cli/install): shallow-clone-safe update, uninstall, checkbox men…",
          "author_name": "Shayan Eskandari",
          "author_login": "shayanb",
          "committed_at": "2026-06-08T22:55:17Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "87f3a74fd65ec45e429744782c0fa6dc34dbd47d",
          "body": null,
          "is_bot": false,
          "headline": "chore: merge latest main (geoip refresh) into dev",
          "author_name": "Shayan Eskandari",
          "author_login": "shayanb",
          "committed_at": "2026-06-08T22:48:22Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "50a6a1707c49bb733593314b0197eac5b640b2bd",
          "body": "CLI wrapper\n- Replace the terse \"drop-in convenience\" help with a banner: MoaV ASCII logo,\n  version (from VERSION), and repo/site links; grouped, relevant command list.\n- `status` is now a formatted Service/Status table plus endpoint health (X/Y +\n  active strategy from the API) and the access URLs\n[…]\nntry covering the installer auto-install + wizard,\n  official Xray image, version pinning, dashboard fixes, and this CLI redesign.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(cli): redesign moav-client wrapper + bump to v1.3.0",
          "author_name": "Shayan Eskandari",
          "author_login": "shayanb",
          "committed_at": "2026-06-08T21:35:52Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "7896f61348bd3d94c77ae99ed8a692fde694740b",
          "body": "…, tab cleanup\n\nInstaller\n- Wizard/confirm prompts now use `read -e` so arrow keys do line-editing\n  instead of injecting ^[[A; make them bold cyan »-prefixed so it's clearly a\n  question awaiting input (covers the build & start confirm).\n- After LAN exposure, detect when the host's primary IP is pu\n[…]\nlone Config tab; fold the config.yaml editor into the bottom\n  of Settings as a collapsible \"advanced — edit config.yaml\" section.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(install/ui): readline prompts, public-IP warning, VPS URL display…",
          "author_name": "Shayan Eskandari",
          "author_login": "shayanb",
          "committed_at": "2026-06-08T16:58:55Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "706dda08a6b846236d107bead3bb8359cd12f0f9",
          "body": null,
          "is_bot": true,
          "headline": "chore(geoip): refresh CIDR lists [skip ci]",
          "author_name": "github-actions[bot]",
          "author_login": "github-actions[bot]",
          "committed_at": "2026-06-08T09:03:27Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c8072d821efb43eff85ee6842db50a4e6cac174f",
          "body": "…g, official xray, LAN exposure\n\nInstaller & wrapper UX\n- Fix the core bug: install.sh went headless under `curl | bash` (stdin not a\n  TTY) and skipped every prompt. Now prefers /dev/tty and only falls back to\n  headless with no terminal at all (genuine cloud-init/CI/cron).\n- Replace the per-item y\n[…]\nintTable surfaces \"run: moav-client sidecar add <kind>\".\n\nDocs: INSTALL.md covers the wizard, expose command, and version pinning.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(install): interactive-when-piped, sidecar wizard, version pinnin…",
          "author_name": "Shayan Eskandari",
          "author_login": "shayanb",
          "committed_at": "2026-06-07T15:40:13Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "5c76de1b15fb82700b6d0efbfccbe18bf51af3e6",
          "body": "The installer previously exited when docker (or git/curl/python3) was\nmissing. It now installs them automatically:\n\n- detect_os() + package-manager helpers (apt/dnf/yum/apk/pacman/brew)\n- install_docker(): Linux via get.docker.com, Alpine via apk, macOS via\n  Homebrew (Docker Desktop); Windows/unkno\n[…]\n\nNew knobs: --yes/-y (MOAV_ASSUME_YES), --no-docker-install\n(MOAV_NO_DOCKER_INSTALL). docs/INSTALL.md updated with platform table.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(install): auto-install missing prerequisites cross-platform",
          "author_name": "Shayan Eskandari",
          "author_login": "shayanb",
          "committed_at": "2026-06-07T14:51:54Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "39d636e4d3dcc81b2e643be62ab2369dd396da79",
          "body": "Document the plugin/routing system end to end: how a decision is made\n(torrent-blocker → first-match-wins chain → default proxy), all match types and\nactions, the hostname-vs-IP caveat, the block-direct kill-switch, geoip, the\nconfig.yaml shape, and the API. Full template catalog in two groups —\nnet\n[…]\nction + dashboard table (drop the removed\nir-geo-proxy, add the selective-app templates) and link the new doc from the\ndocs index.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs: add docs/PLUGINS.md (routing engine + full template catalog)",
          "author_name": "Beezhan",
          "author_login": "ibeezhan",
          "committed_at": "2026-06-06T13:33:24Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "1f90490bbf5ef7f154ba78f1f0e8167ff487df2f",
          "body": "…ync/streaming/games)\n\nCurated destination-based templates to keep specific apps off the VPN or block\ntheir background traffic — the practical approximation of TripMode/WireSock\nper-app tunneling, since a SOCKS5/HTTP proxy sees the destination, not the\noriginating process:\n\n- block-system-updates  →\n[…]\n↔direct, add/remove domains) per the existing template\nflow. Shared-CDN apps can't be isolated this way — documented in each Help.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(plugins): selective-app routing templates (updates/zoom/icloud/s…",
          "author_name": "Beezhan",
          "author_login": "ibeezhan",
          "committed_at": "2026-06-06T13:18:46Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "020b3117b781bae0f34f70c276ffb9b7edd81a37",
          "body": "…label\n\nDistinguish endpoints/sources that came from a MoaV bundle import from pasted\ncustom sources. Paste-added sources are tagged origin=custom; bundle imports and\nlegacy sources default to moav. /api/sources reports is_moav; the Endpoints tab\nprefixes the source with \"moav/\" and the Sources tab shows a \"moav\" badge.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(ui): mark MoaV-bundle sources with a moav badge / moav/<bundle> …",
          "author_name": "Beezhan",
          "author_login": "ibeezhan",
          "committed_at": "2026-06-06T02:52:18Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "7bd76e4f30c279ca5dbbb44ae33f2aa24321edbe",
          "body": "Bump proxy-core Version + web-ui package.json to 1.2.0 and write the 1.2.0\nCHANGELOG section (dashboard login, network exposure controls, responsive\nmobile UI, paste-text sources, source tags + sidecar attribution, rule\npersistence, comment-preserving config writes, and the related fixes).\n\nTag + GitHub release left for manual publishing.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore(release): prepare v1.2.0",
          "author_name": "Beezhan",
          "author_login": "ibeezhan",
          "committed_at": "2026-06-06T02:41:15Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "2de0c12ac5440fa33aca13501201fb483a161337",
          "body": "Naming (display-only; canonical IDs/names untouched for state + dedup):\n- displayEndpointName now strips the MoaV-/-<source> decoration and sidecar-\n  prefix and pretty-cases known kinds, so the Source column owns the bundle and\n  the name is just the label: \"MoaV-Hysteria2-beezhantest2\" → \"Hysteria\n[…]\nest/endpoint to nothing on phones;\n  below 640px each flow is now a stacked row (id+bytes+result, then dest, then\n  the endpoint).\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: bare endpoint names, paste-text sources, readable flows on mobile",
          "author_name": "Beezhan",
          "author_login": "ibeezhan",
          "committed_at": "2026-06-06T02:38:53Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "a15470fd4bd465195b206cb6b14ae1b62bba51e1",
          "body": "The subscription.txt path was noise — the bundle name (card title) plus the\ncomponent tags already convey what a source is. Drop the local file path in\nboth the mobile cards and the desktop table (rename that column \"Components\"),\nkeeping a remote URL when present.\n\n(Generic sidecars like psiphon/tor aren't bundle-attributed — handled by only\ntagging importer-written sidecars; the user's psiphon backfill was removed.)\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(ui): drop local file path from Sources, show URL + tags only",
          "author_name": "Beezhan",
          "author_login": "ibeezhan",
          "committed_at": "2026-06-06T02:24:10Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "4adc318e71400c4d1d76208b1c18f6a5be042b5e",
          "body": "…ad row\n\n- The bundle importer now tags each sidecar config it writes with\n  sidecars.<kind>.config.source = <bundle name>. SidecarManager surfaces that\n  as the endpoint's Source, so the Endpoints tab shows the originating bundle\n  (e.g. \"beezhantest2\") instead of the generic \"sidecars\" group. main\n[…]\npload row: the dropzone goes full-width with the ?/reload buttons on\n  their own row on mobile, instead of three squished columns.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: attribute imported sidecars to their source bundle; mobile uplo…",
          "author_name": "Beezhan",
          "author_login": "ibeezhan",
          "committed_at": "2026-06-06T02:13:40Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "08bcfa5aa109e816eaecdc629d7a4391574d84c6",
          "body": "Both rendered as wide tables that wrapped mid-word on phones (source paths\nbroke like \"subscr/iption.t/xt\", and the per-endpoint status stacked oddly).\nBelow 640px they now render as stacked cards — name + status on top, then the\naddress and the dials/err/failovers/up/down/last stats laid out cleanly — while\nthe desktop tables are unchanged.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "style(ui): card layouts for Sources + Analytics per-endpoint on mobile",
          "author_name": "Beezhan",
          "author_login": "ibeezhan",
          "committed_at": "2026-06-06T01:59:30Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "4855ce8f4f83d8a1caaa3ea74cf85e7564cc7f90",
          "body": "Re-auth prompt: iOS Safari doesn't attach cached basic-auth credentials to a\nWebSocket handshake, so the basic-auth-protected /api/ws got 401'd and Safari\nre-prompted whenever a WS tab (Endpoints / Debug) mounted. Fix with a ticket:\n- proxy-core issues a short-lived single-use ticket at GET /api/ws-\n[…]\nthe header\nshowed \"no endpoints\". App now polls /api/endpoints so the count is always live.\n\nAlso drop two unused WS_BASE imports.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(ui): stop Safari WS re-auth prompt; keep header count on every tab",
          "author_name": "Beezhan",
          "author_login": "ibeezhan",
          "committed_at": "2026-06-06T01:54:26Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "f7fb22e0b3dba592ffcd3286e914b4944c30b331",
          "body": "Comment-preserving YAML:\n- Add a shared yaml.Node-based editor (editYAMLFile + a yamlMap helper) that\n  edits only the nodes it touches, so comments / key order / blank lines in\n  config.yaml round-trip intact instead of being wiped by the old\n  unmarshal-to-map / re-marshal path.\n- Convert all four\n[…]\nored password on save.\n\nAlso update the exposure tests for the reveal-when-authenticated behavior and\nadd a masked-when-open case.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: comment-preserving config writes + disable-auth toggles",
          "author_name": "Beezhan",
          "author_login": "ibeezhan",
          "committed_at": "2026-06-06T01:36:56Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "1a5bda723d01725291f6ee5ebccee2b1385f18cb",
          "body": "…mplate\n\n- Dashboard rule edits (add / remove / enable / disable / reorder) now write\n  back to config.yaml's plugins.routing_rules via PUT /api/plugins, so they\n  survive a proxy-core restart instead of resetting to the on-disk config.\n- RoutingRuleConfig gains `enabled` (pointer → absent defaults \n[…]\nnfig.yaml\").\n\nVerified: a disabled rule persists as disabled across a restart; config.yaml\nround-trips with per-rule enabled/note.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(plugins): persist routing rules to config.yaml; drop ir-proxy te…",
          "author_name": "Beezhan",
          "author_login": "ibeezhan",
          "committed_at": "2026-06-06T01:13:17Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "6db6af5b2864049381c63ddca32add741a29ae50",
          "body": "… clarify templates\n\n- Copy buttons did nothing over plain HTTP on a LAN IP because\n  navigator.clipboard is undefined outside secure contexts. Add a copyText()\n  helper with a hidden-textarea + execCommand fallback; use it in the ACCESS &\n  URLS panel, the recreate-command copy, and Debug's copy-al\n[…]\n match IP\n  literals only (no hostname resolution), and ir-geo-proxy notes it's the\n  inverse of the default 'Iran → direct' rule.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(ui): clipboard fallback over HTTP, refresh URLs on exposure save;…",
          "author_name": "Beezhan",
          "author_login": "ibeezhan",
          "committed_at": "2026-06-06T01:06:03Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "bd0418db3ea026b64bfdcda2696ae17c849166e4",
          "body": "The topbar controls were a single wrapping row that scattered on mobile.\nGroup them: status (clock + health pill) and actions (Refresh + Apply/restart)\nare now distinct rows on phones — health spans the status row, buttons stretch\nfull-width for tap targets — and stay inline on desktop. Slightly larger radius\nto match the pill tabs.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "style(ui): reorganize header into title / status / action groups",
          "author_name": "Beezhan",
          "author_login": "ibeezhan",
          "committed_at": "2026-06-06T00:44:05Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "9f1cb551e8456a5b96ce65cbedc75e63bd867da8",
          "body": "- The selected tab is saved to localStorage and restored on load, so a refresh\n  no longer snaps back to Endpoints.\n- ACCESS & URLS now shows the address appropriate to the exposure mode, using\n  only local signals (no external IP lookup):\n    loopback → 127.0.0.1\n    lan      → the LAN IP you're vi\n[…]\n             clearly-marked placeholder + port-forward note\n  Backend /api/exposure gains lan_ip from a local net.Interfaces scan.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(ui): persist active tab across refresh; mode-relative ACCESS & URLS",
          "author_name": "Beezhan",
          "author_login": "ibeezhan",
          "committed_at": "2026-06-06T00:38:53Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "b1ad987745ab7e5779d7c602ea463c3bd9800919",
          "body": "…pply button\n\nAuth fields (Settings → exposure):\n- Add explicit auth_set / dashboard_set flags so the UI states plainly whether\n  a password is set (✓/✗) instead of an empty field that looked filled because\n  of a •••• placeholder.\n- Password inputs are now type=password with a show/hide toggle.\n- S\n[…]\ning breaks the affected endpoints. (No TLS cert is involved; it's\na uTLS ClientHello-injection passthrough, not a TLS terminator.)\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(ui): clearer auth set-state + reveal, fix URL/footer wrap, SNI a…",
          "author_name": "Beezhan",
          "author_login": "ibeezhan",
          "committed_at": "2026-06-06T00:28:49Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "85d2926dd3370205d472ef91befeefdcb2dc7139",
          "body": "…polish\n\nDashboard auth that actually works:\n- The dashboard now calls /api on its OWN origin; nginx (and the existing Caddy\n  https profile) reverse-proxy /api + /api/ws to proxy-core. Single origin means\n  one set of browser basic-auth creds covers the UI and the API together — the\n  previous dire\n[…]\nno longer overflow the screen (min-width:0 +\n  border-box in the grid).\n- index.html served no-cache so new builds load on mobile.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(auth+ui): working dashboard login (separate from proxy), mobile …",
          "author_name": "Beezhan",
          "author_login": "ibeezhan",
          "committed_at": "2026-06-06T00:09:50Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "c7171f8febe8204609dac317c672e4235037851e",
          "body": "…moav\"\n\n- nginx now serves a custom server block that marks index.html no-cache (so a\n  fresh build's hashed bundle is picked up instead of a stale one cached by\n  mobile Safari) while long-caching the content-hashed assets.\n- SOCKS5 auth defaults the username to \"moav\" when only a password is set, and\n  the exposure form prefills \"moav\" — matching the expected default.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(ui): no-cache index.html so new builds load; default proxy user \"…",
          "author_name": "Beezhan",
          "author_login": "ibeezhan",
          "committed_at": "2026-06-05T23:57:29Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "795232930a974a288fb3f4e32e673c1bc376b678",
          "body": "…ies-auth\n\nMobile:\n- Endpoints render as stacked cards below 640px (was an overflowing table);\n  remaining wide tables (Analytics, Sources) scroll in their own containers.\n- Remove the card-level overflow-x that clipped the block-direct banner; share\n  the useIsMobile hook.\n\nApply without a terminal\n[…]\n (username optional) — both\n  main.go and server.go required both, silently leaving the proxy open when\n  only a password was set.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(ui+auth): mobile card layout, apply-from-dashboard, restart-appl…",
          "author_name": "Beezhan",
          "author_login": "ibeezhan",
          "committed_at": "2026-06-05T23:40:43Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "4832d680639955f5cafc13bb463d608a7e0b87b8",
          "body": "Add a useIsMobile hook and adapt the layout below 640px: the topbar stacks\n(logo/title on one line, controls below) instead of overlapping the clock,\nthe decorative subtitle hides, page + card padding shrink, and wide tables\n(Endpoints, per-endpoint stats) scroll horizontally within the card via\noverflow-x + a min-width instead of overflowing the viewport.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(ui): responsive layout for phones",
          "author_name": "Beezhan",
          "author_login": "ibeezhan",
          "committed_at": "2026-06-05T23:15:30Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "b3e5e0a4653bfa8a9ebfa22f98425df36532f13b",
          "body": "…he dashboard\n\nhandleExposure set SOCKS5_BIND/HTTP_BIND/UI_BIND but not API_BIND, so enabling\nLAN exposure made the dashboard (:3001) reachable while the API (:8088) it\nfetches from stayed loopback — the dashboard loaded over LAN but couldn't get\ndata. Bind API_BIND to the same interface.\n\nAdd an \"a\n[…]\nng that the dashboard is\n:3001 (not :1080, which is the SOCKS5 proxy), with a copy button each and a\nno-auth warning when exposed.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(exposure): bind the API too on lan/public + show access URLs in t…",
          "author_name": "Beezhan",
          "author_login": "ibeezhan",
          "committed_at": "2026-06-05T23:10:56Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "8904976cac106a2d5b00f2bd9c81c69548fd0005",
          "body": "…ealthy\n\nA single transient blip (a momentary Reality handshake failure, a brief\nnetwork hiccup, a sidecar mid-restart) flipped an endpoint to \"error\" for a\nwhole 30s cycle. Retry once (after 300ms) on error/timeout before recording\nthe status; oks aren't retried. Smooths spurious flapping without delaying\ndetection of genuinely-down endpoints.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(prober): retry a failed probe once before marking an endpoint unh…",
          "author_name": "Beezhan",
          "author_login": "ibeezhan",
          "committed_at": "2026-06-05T19:01:37Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "c10eb13bce2b4f7765428c77ec541dbfb5290713",
          "body": "Per the intended default: the single enabled rule out of the box is\n`geoip:ir → direct` (Iranian destinations bypass the proxy, keeping domestic\ntraffic on the real IP to avoid VPN detection + IR-IP blocks). torrent_block\nnow defaults off; enable it and other curated rules from the dashboard.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "config: default to only the Iran-direct rule (torrent_block off)",
          "author_name": "Beezhan",
          "author_login": "ibeezhan",
          "committed_at": "2026-06-05T19:00:27Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "0e7ddbb77e2f4e82b98b2ac56b08804850fdc34e",
          "body": "…y name\n\nSeveral endpoints share a protocol (Reality/CDN/XHTTP are all vless), so the\nbare ID was ambiguous in the logs. Add Endpoint.Label() (\"MoaV-XHTTP-beezhantest2\n(beezhantest2/vless:host:port)\") and use it in the probe + balancer-dial log\nlines so each line identifies which config it's about.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(logs): lead probe/balancer log lines with the endpoint's friendl…",
          "author_name": "Beezhan",
          "author_login": "ibeezhan",
          "committed_at": "2026-06-05T18:50:17Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "0f7caeeb2b5f88155f47cfc12bc64c83112ef4c9",
          "body": "Both ran with no healthcheck, so a misgenerated config or a parse failure\nshowed as a plain \"Up\" rather than unhealthy. Add a config-validity check\n(sing-box check / xray run -test) guarded to stay healthy while an engine is\nlegitimately idling with no config yet.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(compose): healthchecks for sing-box + xray",
          "author_name": "Beezhan",
          "author_login": "ibeezhan",
          "committed_at": "2026-06-05T18:40:09Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "268512cd7144dc5ce07367b22325734e6bcfddc8",
          "body": "…with the TLS check\n\n- A failing probe with status=error now logs at ERROR level (timeout stays\n  warn, ok stays info), so the Debug tab's error filter matches the endpoint's\n  \"error\" status and shows the reason in red.\n- Latency is now measured at the SOCKS CONNECT grant (tunnel establishment),\n  \n[…]\nhe handshake is kept as a pass/fail\n  tunnel-liveness check but no longer ~doubles the reported ping (Reality\n  ~1500ms → ~150ms).\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(debug,prober): probe errors show as ERROR; don't inflate latency …",
          "author_name": "Beezhan",
          "author_login": "ibeezhan",
          "committed_at": "2026-06-05T18:32:53Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "06fab8e7389b4e964252d26efa53a67cb8bf09fa",
          "body": "Two bugs made the Debug tab useless for diagnosing unhealthy endpoints:\n\n1. socksConnect/tcpConnect discarded the dial/handshake error, so a probe\n   line only said \"status=error\" with no cause. They now return the error\n   and ProbeOne logs it (e.g. \"tunnel TLS handshake: connection reset by\n   pee\n[…]\nfore classifying,\n   and flag failing per-endpoint probes (status=error/timeout) as warn so\n   they surface above the info stream.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(debug): surface probe failure reasons as WARN in the log tail",
          "author_name": "Beezhan",
          "author_login": "ibeezhan",
          "committed_at": "2026-06-05T18:23:14Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "3fa6fb84ed3baa9cc76718e69c28c413d8faf835",
          "body": "/api/sources marshaled a nil slice as JSON null; the Sources tab then read\n.length on null and crashed to a blank render. Return [] from the API and\nnormalise null→[] in the component so the empty state (upload area + \"no\nsources\" row) shows correctly.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(sources): blank page when no sources are configured",
          "author_name": "Beezhan",
          "author_login": "ibeezhan",
          "committed_at": "2026-06-05T18:09:47Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "9cb5325156556ac602ad1791b6bff7daeac4624c",
          "body": "…p:ir → direct\n\nThe kill-switch now drops only the balancer's involuntary fallback (all\nendpoints down). A deliberate `direct` rule takes priority and is always\nhonored — so geoip:ir→direct and lan-direct keep working with it on. The\ndashboard toggle now names any enabled `direct` rules when the kil\n[…]\nDefault routing rules trimmed to a single `geoip:ir → direct` (Iranian\ndestinations stay domestic); other templates ship disabled.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(plugins): block_direct honors explicit direct rules; default geoi…",
          "author_name": "Beezhan",
          "author_login": "ibeezhan",
          "committed_at": "2026-06-05T17:30:36Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "bc3e125efb2efe4e66a4b9436b9ed646fc9b1988",
          "body": null,
          "is_bot": false,
          "headline": "docs(changelog): note block-direct dashboard toggle under Unreleased",
          "author_name": "Beezhan",
          "author_login": "ibeezhan",
          "committed_at": "2026-06-05T17:21:59Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "924c15a88d027151c0e916694e1e325371231ff0",
          "body": "…able\n\nSurface block_direct in the UI (it was config-only). New GET/PUT\n/api/block-direct applies the flag live to the rule engine + balancer\n(no restart) and persists to config.yaml. A toggle banner sits above the\nEndpoints table, red-accented when active, with a caption noting it also\ndisables direct routing rules like lan-direct.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(dashboard): block-direct kill-switch toggle above the endpoint t…",
          "author_name": "Beezhan",
          "author_login": "ibeezhan",
          "committed_at": "2026-06-05T17:19:29Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "4eeaf54a88609419f5f02596be5fed04b09cd94e",
          "body": null,
          "is_bot": false,
          "headline": "chore: gitignore .claude agent dir",
          "author_name": "Beezhan",
          "author_login": "ibeezhan",
          "committed_at": "2026-06-05T13:37:16Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b5d25bfc52ee0beadf031ec38d353587be3e08b6",
          "body": "Trim README to essentials; drop stale Known Limitations (xray/reality/amneziawg\nfixed) and the verbose download methodology. Move headless install, Psiphon and\nconfig detail into docs/ (INSTALL, SIDECARS). Rename INTERNALS→ARCHITECTURE, add\nTROUBLESHOOTING, refresh SNI_SPOOFING (both upstreams + source of truth +\nneeds-testing). Add screenshot/gif placeholders. Sync README-fa.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs: lean README + /docs split, screenshot placeholders, Farsi sync",
          "author_name": "Beezhan",
          "author_login": "ibeezhan",
          "committed_at": "2026-06-05T13:37:02Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "138569ed28785f63ef73ef9ffdcb92bb17460b50",
          "body": "Bump version 0.1.0 → 1.0.0 and add CHANGELOG with the 1.0.0 release notes.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore(release): v1.0.0",
          "author_name": "Beezhan",
          "author_login": "ibeezhan",
          "committed_at": "2026-06-05T13:36:50Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "2f470bbcf487e9f9cf4148e0896bbe7f17cf40a4",
          "body": "Symlink the management wrapper into /usr/local/bin (sudo fallback) like moav\ndoes, so it's usable as `moav-client ...` from anywhere. Closing tips use the\nglobal command when available, else ./moav-client.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(install): install moav-client as a global command",
          "author_name": "Beezhan",
          "author_login": "ibeezhan",
          "committed_at": "2026-06-05T13:36:50Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "9223282122bc13bd0e4dc2e4defa27abf298994c",
          "body": "scripts/update-geoip.sh builds geoip/<cc>.txt from arastu/mikrotik-iran-\naddress-list (auto-aggregated) ∪ RIPE country-resource-list, filtered to valid\nIPv4 CIDRs. geoip/ir.txt ships in-repo (~2.3k CIDRs); the update-geoip Action\nrefreshes weekly.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(geoip): ship Iran CIDR list + weekly CI refresh",
          "author_name": "Beezhan",
          "author_login": "ibeezhan",
          "committed_at": "2026-06-05T13:36:50Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "fd516ae880fe5911cb2048916d9f0d7e65443bc6",
          "body": "…to-wire on import\n\n- TrustTunnel: pull the upstream prebuilt Linux client (TrustTunnelClient\n  v1.0.49, Apache-2.0) and run it in SOCKS5 mode. configgen rewrites the\n  bundle's [listener.tun] to a loopback [listener.socks] and socat\n  republishes it on :5600 — no TUN/NET_ADMIN. Verified end-to-end \n[…]\nw wires amneziawg + trusttunnel source_path (like masterdns),\n  so enabling those sidecars after an import needs no manual config.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(sidecars): integrate TrustTunnel client, fix Tor healthcheck, au…",
          "author_name": "Beezhan",
          "author_login": "ibeezhan",
          "committed_at": "2026-06-05T13:36:50Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "e106d332ba36b09d11bd4b3a2c04006ce088be3a",
          "body": "Add real first-install network download figures, measured as the NIC RX\ndelta during a cold `docker builder prune -af` + full rebuild on Ubuntu\n24.04/amd64 (includes Go/Node/Debian base images, Go module + npm + apt\ndownloads, psiphon/amneziawg git clones, and pulled runtime images):\ncore-only ~190 \n[…]\nack ~810 MB. Clarify that the ~4 GB build\ncache is reclaimable and updates re-download only changed layers. Mirror\ninto README-fa.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs: measured install download sizes (per-GB cost)",
          "author_name": "Beezhan",
          "author_login": "ibeezhan",
          "committed_at": "2026-06-04T18:38:52Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "c3b0286238b2281f11ee189f72576d2b00e13366",
          "body": "block_direct (plugins.block_direct, default off): when on, any connection\nthat would go direct — a `direct` routing rule OR the balancer's\nall-endpoints-failed fallback — is dropped instead, so the host never\nmakes an unproxied connection that leaks its real IP. Engine rewrites\nDecisionDirect→Decisi\n[…]\nleak). Verified: a geoip block drops the\nconnection before any dial — the destination never reaches the balancer\nor a direct dial.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(plugins): block_direct kill-switch + make geoip rules actually work",
          "author_name": "Beezhan",
          "author_login": "ibeezhan",
          "committed_at": "2026-06-04T18:32:16Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "da9781f926f89dff76a707e490386c2f15b47a8d",
          "body": "- Resource footprint table now uses measured on-disk sizes (Tor was\n  listed 15 MB but is 85 MB; xray 85→104; etc.) with a network column\n  and RAM guidance.\n- Fix stale references: Tor is peterdavehello/tor-socks-proxy (not arti),\n  analytics chart is overlay (not stacked), Debug uses per-level 800\n[…]\noof, diag, backup, restore,\n  version, flows). Add the healthcheck CLI subcommand.\n- Add README-fa.md (Farsi) + language switcher.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs: accurate resource table, refresh stale bits, add Farsi README",
          "author_name": "Beezhan",
          "author_login": "ibeezhan",
          "committed_at": "2026-06-04T18:07:44Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "28b842805d363f4627fa877149fdc0603500c9fc",
          "body": "proxy-core is FROM scratch (no wget/sh) so the wget-based healthcheck\nalways failed → container stuck \"unhealthy\" while serving fine. Add a\n`healthcheck` subcommand to the binary that hits its own /api/healthz,\nand point the compose healthcheck at it.\n\nweb-ui healthcheck used localhost:3000, which r\n[…]\nginx listens IPv4-only → connection-refused. Use\n127.0.0.1.\n\nFound while bringing the full sidecar stack up on a fresh Ubuntu box.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(health): working container healthchecks",
          "author_name": "Beezhan",
          "author_login": "ibeezhan",
          "committed_at": "2026-06-04T18:07:33Z",
          "body_truncated": true,
          "is_coding_agent": true
        }
      ],
      "releases_count": 4,
      "commits_last_year": 127,
      "latest_release_at": "2026-07-13T21:18:20Z",
      "latest_release_tag": "v1.3.2",
      "releases_from_tags": false,
      "days_since_last_push": 4,
      "active_weeks_last_year": 8,
      "days_since_latest_release": 11,
      "mean_days_between_releases": 12.7
    },
    "community": {
      "has_readme": true,
      "has_license": true,
      "has_description": true,
      "has_contributing": false,
      "health_percentage": 37,
      "has_issue_template": false,
      "has_code_of_conduct": false,
      "has_pull_request_template": false
    },
    "ecosystem": {
      "packages": []
    },
    "popularity": {
      "forks": 1,
      "stars": 6,
      "watchers": 1,
      "fork_history": {
        "days": [
          {
            "date": "2026-07-16",
            "count": 1
          }
        ],
        "complete": true,
        "collected": 1,
        "total_forks": 1
      },
      "star_history": null,
      "open_issues_and_prs": 2
    },
    "ai_readiness": {
      "has_nix": false,
      "example_dirs": [],
      "has_llms_txt": false,
      "has_dockerfile": true,
      "has_mcp_signal": false,
      "bootstrap_files": [],
      "api_schema_files": [],
      "has_devcontainer": false,
      "typecheck_configs": [
        "web-ui/tsconfig.json"
      ],
      "toolchain_manifests": [
        "proxy-core/go.mod"
      ],
      "largest_source_bytes": 62396,
      "source_files_sampled": 81,
      "oversized_source_files": 1,
      "agent_instruction_files": [
        "CLAUDE.md"
      ],
      "agent_instruction_max_bytes": 18574
    },
    "dependencies": {
      "manifests": [
        "proxy-core/go.mod",
        "web-ui/package.json"
      ],
      "advisories": {
        "error": null,
        "scope": null,
        "source": null,
        "findings": [],
        "collected": false,
        "malicious": [],
        "truncated": false,
        "by_severity": {},
        "advisory_count": 0,
        "affected_count": 0,
        "assessed_count": 0,
        "malicious_count": 0,
        "assessed_package": null,
        "unassessed_count": 0,
        "direct_affected_count": 0
      },
      "ecosystems": [
        "go",
        "npm"
      ],
      "dependencies": [
        {
          "name": "github.com/armon/go-socks5",
          "manifest": "proxy-core/go.mod",
          "ecosystem": "go",
          "version_constraint": "v0.0.0-20160902184237-e75332964ef5"
        },
        {
          "name": "gopkg.in/yaml.v3",
          "manifest": "proxy-core/go.mod",
          "ecosystem": "go",
          "version_constraint": "v3.0.1"
        },
        {
          "name": "react",
          "manifest": "web-ui/package.json",
          "ecosystem": "npm",
          "version_constraint": "^18.3.1"
        },
        {
          "name": "react-dom",
          "manifest": "web-ui/package.json",
          "ecosystem": "npm",
          "version_constraint": "^18.3.1"
        }
      ],
      "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": 2,
        "closed_ratio": 0.5,
        "closed_issues": 2,
        "closed_unmerged_prs": 0
      },
      "bus_factor": 1,
      "bot_contributors": 1,
      "top_contributors": [
        {
          "type": "User",
          "login": "ibeezhan",
          "commits": 71,
          "avatar_url": "https://avatars.githubusercontent.com/u/279766379?v=4"
        },
        {
          "type": "User",
          "login": "shayanb",
          "commits": 49,
          "avatar_url": "https://avatars.githubusercontent.com/u/309108?v=4"
        }
      ],
      "contributors_sampled": 2,
      "top_contributor_share": 0.592
    },
    "quality_signals": {
      "has_ci": true,
      "has_tests": true,
      "ci_workflows": [
        "ci.yml",
        "e2e.yml",
        "publish-install.yml",
        "telegram-notify.yml",
        "update-geoip.yml"
      ],
      "has_docs_dir": true,
      "linter_configs": [],
      "has_editorconfig": false,
      "has_linter_config": false,
      "has_precommit_config": false
    },
    "security_signals": {
      "lockfiles": [
        "go.sum",
        "package-lock.json"
      ],
      "scorecard": {
        "checks": [
          {
            "name": "Binary-Artifacts",
            "score": 10,
            "reason": "no binaries found in the repo",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#binary-artifacts"
          },
          {
            "name": "Branch-Protection",
            "score": 0,
            "reason": "branch protection not enabled on development/release branches",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#branch-protection"
          },
          {
            "name": "CI-Tests",
            "score": 10,
            "reason": "8 out of 8 merged PRs checked by a CI test -- score normalized to 10",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#ci-tests"
          },
          {
            "name": "CII-Best-Practices",
            "score": 0,
            "reason": "no effort to earn an OpenSSF best practices badge detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#cii-best-practices"
          },
          {
            "name": "Code-Review",
            "score": 0,
            "reason": "Found 1/13 approved changesets -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#code-review"
          },
          {
            "name": "Contributors",
            "score": 10,
            "reason": "project has 12 contributing companies or organizations",
            "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": 10,
            "reason": "license file detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#license"
          },
          {
            "name": "Maintained",
            "score": 0,
            "reason": "project was created within the last 90 days. Please review its contents carefully",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#maintained"
          },
          {
            "name": "Packaging",
            "score": null,
            "reason": "packaging workflow not 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": null,
            "reason": "no releases found",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#signed-releases"
          },
          {
            "name": "Token-Permissions",
            "score": 0,
            "reason": "detected GitHub workflow tokens with excessive permissions",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#token-permissions"
          },
          {
            "name": "Vulnerabilities",
            "score": 2,
            "reason": "8 existing vulnerabilities detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#vulnerabilities"
          }
        ],
        "commit": "0c24d7c076624f60a176dbbbb55c86c27ab20251",
        "ran_at": "2026-07-25T00:36:32Z",
        "aggregate_score": 2.9,
        "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": null,
      "oldest_open_prs": [],
      "last_merged_pr_at": "2026-07-17T17:27:07Z",
      "ci_last_conclusion": null,
      "oldest_open_issues": [
        {
          "number": 1,
          "created_at": "2026-06-02T22:59:24Z",
          "last_comment_at": "2026-07-14T16:40:39Z",
          "last_comment_author": "shayanb"
        },
        {
          "number": 2,
          "created_at": "2026-06-06T00:43:54Z",
          "last_comment_at": null,
          "last_comment_author": null
        }
      ]
    }
  },
  "config": {
    "disabled_metrics": [],
    "disabled_categories": [],
    "disabled_components": {}
  },
  "source": {
    "url": "https://github.com/MotherofallVPNs/moav-client",
    "host": "github.com",
    "name": "moav-client",
    "owner": "MotherofallVPNs"
  },
  "metrics": {
    "overall": {
      "key": "overall",
      "band": "moderate",
      "name": "Overall health",
      "note": null,
      "notes": [],
      "value": 50,
      "inputs": {
        "security": 29,
        "vitality": 76,
        "community": 29,
        "governance": 43,
        "engineering": 67
      },
      "components": []
    },
    "categories": [
      {
        "key": "vitality",
        "band": "good",
        "name": "Vitality",
        "value": 76,
        "weight": 0.22,
        "metrics": [
          {
            "key": "development_activity",
            "band": "moderate",
            "name": "Development activity",
            "note": null,
            "notes": [],
            "value": 60,
            "inputs": {
              "commits_last_year": 127,
              "human_commit_share": 0.93,
              "days_since_last_push": 4,
              "active_weeks_last_year": 8
            },
            "components": [
              {
                "key": "push_recency",
                "name": "Push recency",
                "detail": "last push 4 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "push_recency",
                    "params": {
                      "days": 4
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_cadence",
                "name": "Commit cadence",
                "detail": "8/52 weeks with commits",
                "points": 5.5,
                "status": "partial",
                "details": [
                  {
                    "code": "commit_cadence_weeks",
                    "params": {
                      "weeks": 8
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_volume",
                "name": "Commit volume",
                "detail": "127 commits in the last year",
                "points": 18,
                "status": "met",
                "details": [
                  {
                    "code": "commits_last_year",
                    "params": {
                      "count": 127
                    }
                  }
                ],
                "max_points": 18
              },
              {
                "key": "openssf_scorecard_maintained",
                "name": "OpenSSF Scorecard: Maintained",
                "detail": "project was created within the last 90 days. Please review its contents carefully",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "release_discipline",
            "band": "excellent",
            "name": "Release discipline",
            "note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: Signed-Releases. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "openssf_scorecard_signed_releases"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 100,
            "inputs": {
              "releases_count": 4,
              "latest_release_tag": "v1.3.2",
              "releases_from_tags": false,
              "days_since_latest_release": 11,
              "mean_days_between_releases": 12.7
            },
            "components": [
              {
                "key": "ships_releases",
                "name": "Ships releases",
                "detail": "4 releases published",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "releases_published",
                    "params": {
                      "count": 4
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "release_recency",
                "name": "Release recency",
                "detail": "latest release 11 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "release_recency",
                    "params": {
                      "days": 11
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "release_cadence",
                "name": "Release cadence",
                "detail": "a release every ~12.7 days",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "release_cadence",
                    "params": {
                      "gap": 12.7
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "openssf_scorecard_signed_releases",
                "name": "OpenSSF Scorecard: Signed-Releases",
                "detail": "no releases found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 10
              }
            ]
          },
          {
            "key": "abandonment",
            "band": "excellent",
            "name": "Abandonment",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "cap": null,
              "state": "unverified",
              "guards": [],
              "signals": [],
              "red_flag": false,
              "multiplier_pct": 100,
              "declared_reason": null,
              "unverified_reason": "repository_too_young",
              "unanswered_open_prs": null,
              "unanswered_open_issues": null,
              "days_since_last_merged_pr": null,
              "days_since_last_human_commit": null,
              "days_since_last_human_commit_is_floor": false
            },
            "components": [
              {
                "key": "project_is_still_maintained",
                "name": "Project is still maintained",
                "detail": "maintenance record not established from the collected data",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "abandonment_unverified",
                    "params": {}
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "description": "Is the project alive — is code being written and are releases shipping?"
      },
      {
        "key": "community",
        "band": "critical",
        "name": "Community & Adoption",
        "value": 29,
        "weight": 0.18,
        "metrics": [
          {
            "key": "popularity",
            "band": "critical",
            "name": "Popularity & adoption",
            "note": null,
            "notes": [],
            "value": 11,
            "inputs": {
              "forks": 1,
              "stars": 6,
              "watchers": 1,
              "growth_state": "unverified",
              "growth_factor_pct": 100,
              "growth_unverified_reason": "no_history"
            },
            "components": [
              {
                "key": "stars",
                "name": "Stars",
                "detail": "6 stars",
                "points": 11.3,
                "status": "partial",
                "details": [
                  {
                    "code": "stars",
                    "params": {
                      "count": 6
                    }
                  }
                ],
                "max_points": 60
              },
              {
                "key": "forks",
                "name": "Forks",
                "detail": "1 forks",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "forks",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "watchers",
                "name": "Watchers",
                "detail": "1 watchers",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "watchers",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "max_points": 15
              }
            ]
          },
          {
            "key": "community_health",
            "band": "moderate",
            "name": "Community health",
            "note": null,
            "notes": [],
            "value": 50,
            "inputs": {
              "has_readme": true,
              "has_license": true,
              "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": "recognized license (MIT)",
                "points": 22.5,
                "status": "met",
                "details": [
                  {
                    "code": "license_standard",
                    "params": {}
                  },
                  {
                    "code": "license_spdx",
                    "params": {
                      "spdx": "MIT"
                    }
                  }
                ],
                "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": "at_risk",
        "name": "Sustainability & Governance",
        "value": 43,
        "weight": 0.24,
        "metrics": [
          {
            "key": "maintainer_resilience",
            "band": "at_risk",
            "name": "Maintainer resilience (bus factor)",
            "note": null,
            "notes": [],
            "value": 31,
            "inputs": {
              "bus_factor": 1,
              "contributors_sampled": 2,
              "top_contributor_share": 0.592
            },
            "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 59% of commits",
                "points": 9.2,
                "status": "partial",
                "details": [
                  {
                    "code": "top_contributor_share",
                    "params": {
                      "share": 59
                    }
                  }
                ],
                "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 12 contributing companies or organizations",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "responsiveness",
            "band": "moderate",
            "name": "Issue & PR responsiveness",
            "note": null,
            "notes": [],
            "value": 62,
            "inputs": {
              "merged_prs": 12,
              "open_issues": 2,
              "closed_issues": 2,
              "issue_closed_ratio": 0.5,
              "closed_unmerged_prs": 0
            },
            "components": [
              {
                "key": "issue_resolution",
                "name": "Issue resolution",
                "detail": "50% of issues closed",
                "points": 23.4,
                "status": "partial",
                "details": [
                  {
                    "code": "issues_closed_share",
                    "params": {
                      "share": 50
                    }
                  }
                ],
                "max_points": 46.75
              },
              {
                "key": "pr_acceptance",
                "name": "PR acceptance",
                "detail": "12/12 decided PRs merged",
                "points": 38.2,
                "status": "met",
                "details": [
                  {
                    "code": "decided_prs_merged",
                    "params": {
                      "merged": 12,
                      "decided": 12
                    }
                  }
                ],
                "max_points": 38.25
              },
              {
                "key": "openssf_scorecard_code_review",
                "name": "OpenSSF Scorecard: Code-Review",
                "detail": "Found 1/13 approved changesets -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              }
            ]
          },
          {
            "key": "stewardship",
            "band": "at_risk",
            "name": "Ownership & stewardship",
            "note": null,
            "notes": [],
            "value": 38,
            "inputs": {
              "followers": 2,
              "owner_type": "Organization",
              "is_verified": null,
              "owner_login": "MotherofallVPNs",
              "public_repos": 3,
              "account_age_days": 52
            },
            "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 MotherofallVPNs",
                "points": 3.4,
                "status": "partial",
                "details": [
                  {
                    "code": "owner_followers",
                    "params": {
                      "count": 2,
                      "login": "MotherofallVPNs"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "track_record",
                "name": "Track record",
                "detail": "3 public repos, account ~0 yr old",
                "points": 4.7,
                "status": "partial",
                "details": [
                  {
                    "code": "public_repos",
                    "params": {
                      "count": 3
                    }
                  },
                  {
                    "code": "account_age_years",
                    "params": {
                      "years": 0
                    }
                  }
                ],
                "max_points": 25
              }
            ]
          }
        ],
        "description": "Will the project survive its people — bus factor, responsiveness, who backs it, and package upkeep?"
      },
      {
        "key": "engineering",
        "band": "moderate",
        "name": "Engineering Quality",
        "value": 67,
        "weight": 0.2,
        "metrics": [
          {
            "key": "engineering_practices",
            "band": "moderate",
            "name": "Engineering practices",
            "note": null,
            "notes": [],
            "value": 68,
            "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": "5 workflow(s)",
                "points": 24,
                "status": "met",
                "details": [
                  {
                    "code": "ci_workflows",
                    "params": {
                      "count": 5
                    }
                  }
                ],
                "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": "8 out of 8 merged PRs checked by a CI test -- score normalized to 10",
                "points": 20,
                "status": "met",
                "details": [],
                "max_points": 20
              }
            ]
          },
          {
            "key": "documentation",
            "band": "moderate",
            "name": "Documentation",
            "note": null,
            "notes": [],
            "value": 65,
            "inputs": {
              "topics": [],
              "has_wiki": false,
              "homepage": null,
              "has_readme": true,
              "has_docs_dir": true,
              "has_description": true
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 30,
                "status": "met",
                "details": [],
                "max_points": 30
              },
              {
                "key": "documentation_directory",
                "name": "Documentation directory",
                "detail": null,
                "points": 25,
                "status": "met",
                "details": [],
                "max_points": 25
              },
              {
                "key": "documentation_homepage_site",
                "name": "Documentation / homepage site",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              },
              {
                "key": "repository_description",
                "name": "Repository description",
                "detail": null,
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              },
              {
                "key": "topics",
                "name": "Topics",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              },
              {
                "key": "wiki",
                "name": "Wiki",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          }
        ],
        "description": "Are baseline engineering and documentation practices in place?"
      },
      {
        "key": "security",
        "band": "critical",
        "name": "Security",
        "value": 29,
        "weight": 0.16,
        "metrics": [
          {
            "key": "security_posture",
            "band": "critical",
            "name": "Security posture",
            "note": "Excluded from scoring (no data or not applicable): Packaging, Signed-Releases. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "packaging",
                    "signed_releases"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 29,
            "inputs": {
              "source": "openssf_scorecard",
              "checks_evaluated": 16,
              "scorecard_version": "v5.5.0",
              "checks_inconclusive": 2,
              "scorecard_aggregate": 2.9
            },
            "components": [
              {
                "key": "binary_artifacts",
                "name": "Binary-Artifacts",
                "detail": "no binaries found in the repo",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "branch_protection",
                "name": "Branch-Protection",
                "detail": "branch protection not enabled on development/release branches",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "ci_tests",
                "name": "CI-Tests",
                "detail": "8 out of 8 merged PRs checked by a CI test -- score normalized to 10",
                "points": 2.5,
                "status": "met",
                "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 1/13 approved changesets -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "contributors",
                "name": "Contributors",
                "detail": "project has 12 contributing companies or organizations",
                "points": 2.5,
                "status": "met",
                "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 detected",
                "points": 2.5,
                "status": "met",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "maintained",
                "name": "Maintained",
                "detail": "project was created within the last 90 days. Please review its contents carefully",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "packaging",
                "name": "Packaging",
                "detail": "packaging workflow not detected",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "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": "no releases found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 7.5
              },
              {
                "key": "token_permissions",
                "name": "Token-Permissions",
                "detail": "detected GitHub workflow tokens with excessive permissions",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "vulnerabilities",
                "name": "Vulnerabilities",
                "detail": "8 existing vulnerabilities detected",
                "points": 1.5,
                "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": 4
            },
            "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": 79,
        "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.978,
              "agent_instruction_files": [
                "CLAUDE.md"
              ],
              "agent_instruction_max_bytes": 18574
            },
            "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": "91 of 93 human commits state their intent (structured subject or explanatory body)",
                "points": 40,
                "status": "met",
                "details": [
                  {
                    "code": "legible_history",
                    "params": {
                      "legible": 91,
                      "sampled": 93
                    }
                  }
                ],
                "max_points": 40
              }
            ]
          },
          {
            "key": "ai_verify_loop",
            "band": "moderate",
            "name": "Verify loop (build / test / typecheck)",
            "note": null,
            "notes": [],
            "value": 66,
            "inputs": {
              "has_nix": false,
              "has_tests": true,
              "lockfiles": [
                "go.sum",
                "package-lock.json"
              ],
              "has_dockerfile": true,
              "typed_language": true,
              "bootstrap_files": [],
              "has_devcontainer": false,
              "has_linter_config": false,
              "typecheck_configs": [
                "web-ui/tsconfig.json"
              ],
              "agent_commit_share": 0.73,
              "toolchain_manifests": [
                "proxy-core/go.mod"
              ],
              "dependency_bot_commit_share": 0
            },
            "components": [
              {
                "key": "one_command_bootstrap",
                "name": "One-command bootstrap",
                "detail": "proxy-core/go.mod (toolchain convention, no task runner)",
                "points": 12.6,
                "status": "partial",
                "details": [
                  {
                    "code": "toolchain_convention",
                    "params": {
                      "files": "proxy-core/go.mod"
                    }
                  }
                ],
                "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": "web-ui/tsconfig.json",
                "points": 11,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "web-ui/tsconfig.json"
                    }
                  }
                ],
                "max_points": 11
              },
              {
                "key": "reproducible_environment",
                "name": "Reproducible environment",
                "detail": "Dockerfile, lockfile",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "Dockerfile, lockfile"
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "demonstrated_agent_practice",
                "name": "Demonstrated agent practice",
                "detail": "73 of the last 100 commits agent-authored or agent-credited",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "agent_authored_commits",
                    "params": {
                      "count": 73,
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "automated_maintenance",
                "name": "Automated maintenance",
                "detail": "no automated dependency updates observed",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_dependency_automation",
                    "params": {}
                  }
                ],
                "max_points": 8
              },
              {
                "key": "openssf_scorecard_pinned_dependencies",
                "name": "OpenSSF Scorecard: Pinned-Dependencies",
                "detail": "dependency not pinned by hash detected -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "ai_code_legibility",
            "band": "excellent",
            "name": "Code legibility for models",
            "note": null,
            "notes": [],
            "value": 99,
            "inputs": {
              "primary_language": "Go",
              "largest_source_bytes": 62396,
              "source_files_sampled": 81,
              "oversized_source_files": 1
            },
            "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": "1/81 source files over 60KB",
                "points": 54.3,
                "status": "partial",
                "details": [
                  {
                    "code": "oversized_source_files",
                    "params": {
                      "kb": 60,
                      "sampled": 81,
                      "oversized": 1
                    }
                  }
                ],
                "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",
    "Could not fetch go package 'github.com/ibeezhan/moav-client/proxy-core' from its registry",
    "GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository"
  ],
  "report_type": "repository",
  "generated_at": "2026-07-25T00:36:45.728812Z",
  "schema_version": "0.27.0",
  "badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/m/MotherofallVPNs/moav-client.svg",
  "full_name": "MotherofallVPNs/moav-client",
  "license_state": "standard",
  "license_spdx": "MIT"
}

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