afip-constancia — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited afip-constancia (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Drive the public ARCA Constancia de Inscripción form and return one JSON envelope: the parsed constancia plus the official PDF. No Clave Fiscal — this is the form any citizen can use with just a CUIT.
Required: BROWSERBASE_API_KEY env var and browse CLI installed.
Typed companion: the same lookup is available as a typed, testable npm package — @ar-agents/constancia, part of the Arg toolkit — for agents on the Vercel AI SDK. Both share the Output contract below (parseSkillOutput). One artifact, two surfaces: use the package for programmatic/Vercel-AI use, this skill for any browser-driving agent.
When NOT to use this skill: if the caller only needs the data (not the PDF) and has an AFIP X.509 cert provisioned, the SOAP padrón webservice (@ar-agents/identity lookup_cuit_afip) is faster and needs no browser. This skill's edge is the PDF artifact and the no-cert path.
Print exactly one JSON object to stdout as the last line, nothing after it. Shape:
{
"cuit": "20123456786",
"found": true,
"denominacion": "APELLIDO NOMBRE | RAZÓN SOCIAL",
"tipoPersona": "fisica | juridica",
"condicion": "Monotributo | Responsable Inscripto | Exento | No Alcanzado | Sin inscripción",
"monotributoCategoria": "A",
"domicilioFiscal": { "direccion": "", "localidad": "", "provincia": "", "codigoPostal": "" },
"actividades": [{ "codigo": "620100", "descripcion": "", "principal": true }],
"impuestos": [{ "descripcion": "MONOTRIBUTO", "desde": "2026-04-17" }],
"fechaInscripcion": "2026-04-17",
"estado": "ACTIVO",
"pdf": { "base64": "JVBERi0x…", "url": "", "codigoVerificador": "" }
}Rules:
{ "cuit": "...", "found": false } (nothing elserequired). Do not invent a constancia.
"<short reason>" }. If the page literally says the CUIT no figura inscripto, put that text in error — the parser maps "no figura / not found / inexistente" to a clean cuit_not_found`.
condicion is free text — emit what the page shows; the parser normalizes it.pdf.base64 is preferred (durable). pdf.url only if you cannot capturebytes (ARCA PDF URLs are short-lived). Include codigoVerificador when the document prints one.
CUIT_RAW="$1"
CUIT="$(printf '%s' "$CUIT_RAW" | tr -cd '0-9')"If CUIT is not exactly 11 digits, emit {"cuit":"<raw>","error":"invalid_cuit: not 11 digits"} and stop. Do not open a browser for a malformed CUIT — browser runs are expensive and ARCA throttles.
Start a cloud session and open the public entry point (no auth):
browse open "https://www.afip.gob.ar/genericos/constanciainscripcion/" --cloudDo not hardcode internal POST endpoints — ARCA rotates them. Navigate via the on-page elements. Locate the control that begins the consulta (a "Consultar" / "Ingresar" button or a CUIT field) semantically, not by a brittle fixed selector:
browse snapshot # inspect the live DOMType the 11-digit CUIT into the CUIT/identification field and submit. If a captcha / "no soy un robot" appears, rely on the Browserbase verified session + CAPTCHA solving (see the browser skill); do not attempt to bypass it manually. If it still blocks, emit {"cuit":"<cuit>","error":"captcha_blocked"} and stop.
If the result page states the CUIT is not registered / "no figura inscripto" / "inexistente", emit {"cuit":"<cuit>","found":false} and stop. This is a normal, expected outcome — not an error.
From the rendered constancia, read: denominación, persona física vs jurídica, condición/régimen, monotributo categoría (if shown), domicilio fiscal, actividades (código + descripción + which is principal), impuestos (+ fecha desde), fecha de inscripción, estado, and the código verificador. Dump the raw page text/DOM to a temp file — do not hand-parse in a fragile pipeline:
browse get markdown > /tmp/constancia_${CUIT}.txtTrigger the constancia's print/PDF action and capture the document as bytes:
browse pdf --output /tmp/constancia_${CUIT}.pdf
PDF_B64="$(base64 -i /tmp/constancia_${CUIT}.pdf | tr -d '\n')"If byte capture is impossible, fall back to the visible PDF URL. A constancia without its PDF is still useful — never discard the parsed data because the PDF step failed; just omit pdf or set error only if nothing was obtained.
Build the JSON per the Output contract from the extracted fields + the base64 PDF, and print it as the final stdout line via the helper (it enforces the exact shape the companion package expects):
node "$(dirname "$0")/scripts/emit_constancia.mjs" /tmp/constancia_fields_${CUIT}.jsonafip.gob.ar. Treat the names as interchangeable.
page is unrecognizable, emit error: "fetcher_unexpected_response: <detail>" rather than guessing — the companion package treats wrong data as worse than no data.
browser server-side / in Browserbase (this skill does, via --cloud).
decides freshness policy.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.