Important
This is an unofficial personal project and is not affiliated with, endorsed by, or supported by UFPB, SIGAA, or SIPAC. Use it responsibly, keep request rates low, and follow the rules that apply to your SIGAA account. See Privacidade e segurança for what is stored and what is never stored.
Friendly CLI and MCP server for SIGAA UFPB and SIPAC public process lookup. Fetch your classes, grades, deadlines, and curriculum all at once without opening the web portal.
Step 1: Install uv (once only):
brew install uv
# or: curl -LsSf https://astral.sh/uv/install.sh | shStep 2: Install sigaa:
uv tool install "sigaa-tools[mcp] @ git+https://github.com/PucaVaz/sigaa-tools"Step 3: Run the setup wizard:
sigaa initThat's it. The wizard prompts for your SIGAA credentials, stores them securely, syncs your data, and optionally sets up MCP for Claude Code or background polling.
- CLI:
sigaa classes,sigaa news,sigaa grades,sigaa deadlines, etc. Fast, offline-first queries from a local SQLite database. - MCP server: Wire into Claude Code (or any MCP client) to let AI agents fetch your SIGAA data on demand.
- SIPAC lookup:
sigaa sipac process 23074.056437/2026-26— look up public UFPB administrative processes without a browser.
sigaa sync # fetch & persist new news, deadlines, grades
sigaa sync --bodies # also fetch full news article text
sigaa classes --schedule # enrolled classes with decoded weekly schedule
sigaa news --class DSCO00022 # news for one class
sigaa news --unread --mark-seen
sigaa grades --semester 2025.1 # grades by semester
sigaa deadlines # assessment/task due dates
sigaa ics --out sigaa.ics # export classes + deadlines as calendar
sigaa curriculum # live progress & required courses
sigaa cra --json # official CRA as JSON
sigaa extensao # extension participations + available declarations/certificates
sigaa selecao-extensao --search trilha # extension actions open for selection
sigaa watch --once --json # sync and report changes as JSON (see Notifications)Store-backed commands (classes, news, grades, deadlines) are fast and offline. Network commands (sync, watch, curriculum, cra, extensao, selecao-extensao, downloads) need internet.
Use this feature to follow UFPB administrative processes without opening each SIPAC page manually. Look up one process by its complete number or find processes by an interested party name or identifier. Process details include the current status, subject, interested parties, public documents, routing movements, status changes, and attached files.
sigaa sipac process 23074.056437/2026-26
sigaa sipac process 23074.056437/2026-26 --json
sigaa sipac search --name "Fulano de Tal"
sigaa sipac search --identifier "12345678901" --page 2 --jsonExample summary:
23074.056437/2026-26 [ATIVO]
ANÁLISE DE PROPOSTA DE RESOLUÇÃO SOBRE DISTRIBUIÇÃO DE ENCARGOS DIDÁTICOS
Origin: CI - DIREÇÃO DE CENTRO (11.01.45.01)
Opened: 12/06/2026 17:26
Interested parties: 1 | Documents: 14 | Movements: 6
Agents can call sipac_get_public_process with {"number": "23074.056437/2026-26"}. To search, call sipac_search_public_processes with either name or identifier. Both interfaces use the same schema_version: 1 contracts as the CLI JSON output. Public SIPAC commands do not authenticate, bypass restricted documents, change processes, or persist results. See the SIPAC process guide for fields, use cases, privacy guidance, and error handling.
Headless fallback: export SIGAA_USER=... SIGAA_PASS=....
Optional SIGAA_DB=/path/to/sigaa.db to override the store location.
Run sigaa init; it can detect or create .mcp.json and add the sigaa MCP
server without manual absolute-path editing.
Tools: sigaa_list_classes, sigaa_list_news, sigaa_get_news_body,
sigaa_get_schedule, sigaa_list_grades, sigaa_list_deadlines,
sigaa_get_curriculum, sigaa_get_cra, sigaa_list_extension_participations,
sigaa_search_extension_opportunities, sigaa_apply_extension_selection,
sigaa_find_classmate, sigaa_export_ics,
sipac_get_public_process, sipac_search_public_processes,
sigaa_download_historico,
sigaa_download_declaracao_vinculo, sigaa_download_atestado_matricula,
sigaa_sync. Store-backed reads are offline; sync, live lookups, and downloads
touch the network.
sipac_get_public_process(number) returns the public process metadata exposed
by UFPB: general data, interested parties, documents and public download links,
movements, status changes, and attached files. It shares schema version 1 with
sigaa sipac process --json and does not require credentials.
sipac_search_public_processes(name?, identifier?, page=1) finds public
processes by one interested-party field. Pass exactly one of name or
identifier. Each response contains at most the 15 results exposed by one
portal page. Results are not retained after the request finishes.
Identifiers such as CPF, registration number, and CNPJ are personal data. Query
them only for a legitimate purpose and avoid copying them into logs.
sigaa_get_curriculum is networked and uses the same normalized contract and
filters as sigaa curriculum: status, required_only, period,
include_requirements, and include_cra. Its default current view contains
enrolled components plus required pending ones. Pending optional components are
choices toward the remaining optional workload, not courses that must all be
completed. sigaa_get_cra is also networked and reads the official CRA from the
academic transcript; a new student may receive source: "unavailable" until
SIGAA reports one. Neither response exposes SIGAA's internal student id.
sigaa_list_extension_participations is networked and read-only. It returns the
same contract as sigaa extensao --json: every extension participation (team
member, audience, extension student) with declaration_available and
certificate_available flags that mirror the icons SIGAA shows right now. It
never issues or downloads a document, so it stays available in hosted mode. See
docs/extensao.mdx.
sigaa_search_extension_opportunities(query, year?) searches the extension
actions open for student selection and returns each opportunity_id.
sigaa_apply_extension_selection(opportunity_id, qualifications, lattes_url?, year?, confirm=false) is the one tool that writes to SIGAA: with
confirm=true it presses "Registrar-se como Interessado" and the coordinator
reads the qualifications text. Without confirm it only previews the action.
status is registered only when SIGAA itself reports success. Same contract
as sigaa selecao-extensao.
Every download tool accepts a safe filename (not an arbitrary path), never
overwrites, and writes under the app's private downloads directory. This
covers the three academic documents plus sigaa_download_material and
sigaa_download_tarefa_anexo; on those two the parameter is named filename
and no longer accepts a path. Filenames SIGAA supplies in Content-Disposition
are sanitized rather than trusted. Set
SIGAA_DOWNLOAD_DIR on the MCP server to choose another directory. A successful
call returns both structured metadata (filename, MIME type, and size) and
an opaque MCP ResourceLink. Clients that support resource links can present the
document as an attachment or download; opening it reads the saved file through
MCP without putting its bytes in the original tool response. The resource link is
valid for the current server session, while the local file remains on disk. HTML
certificates are exposed as download-only binary resources so an MCP client does
not execute the report's active SIGAA markup inline.
SIGAA_MODE picks which tools the MCP server exposes. It defaults to local,
which exposes all 26 tools — nothing is ever removed from a local or
self-hosted install.
SIGAA_MODE=hosted is for a shared, multi-tenant deployment. It withholds the
five tools that write files to the server's disk:
| Withheld in hosted | Why |
|---|---|
sigaa_download_material |
Unbounded file writes; a class can hold hundreds of MB |
sigaa_download_tarefa_anexo |
Same |
sigaa_download_historico |
Needs a per-tenant download directory, which does not exist yet |
sigaa_download_declaracao_vinculo |
Same |
sigaa_download_atestado_matricula |
Same |
Everything else stays, including sigaa_sync — without it a tenant's store is
empty and every store-backed tool returns nothing. Its writes are confined to
SIGAA_DB. No MCP tool mutates SIGAA state in any mode: enrollment
selection and confirmation are deliberately CLI-only.
The mode is applied at import, so it holds whether the server is started via
sigaa-mcp, python -m sigaa.mcp_server, or by importing mcp from
sigaa.mcp_server and mounting it. Withheld tools are removed from the tool
manager, so they are uncallable rather than merely hidden. An unrecognized
SIGAA_MODE raises at startup instead of falling back to local.
A hosted deployment must also set SIGAA_DB and SIGAA_DOWNLOAD_DIR per
tenant. Restoring the three academic-document tools in hosted mode depends on
that isolation existing first.
Run sigaa init; it can write the launchd plist on macOS or print the cron
entry for other operating systems.
sigaa watch is the integration point for cron, systemd, and chat bridges. It
syncs, then prints what changed since its previous run as JSON events; no LLM is
involved in deciding whether something changed.
sigaa login # password + account into the OS keyring
sigaa sync --bodies --json # expect "ok": true
sigaa watch --once --baseline --json # optional: skip what is already stored
sigaa watch --once --bodies --json --fail-on-error # schedule this- stdout carries only JSON; human messages go to stderr.
- A run with nothing new reports
"status": "no_changes". - A failed run reports
"status": "failed"pluserrorevents tagged with astage(auth,network,parse,sync) and, with--fail-on-error, exits 1. A failure is never reported asno_changes. - A class page whose news panel cannot be read is a
parseerror, not an empty class. - Unchanged state prints identical bytes, so hash-based monitors are safe.
--jsonl prints one event per line (for --interval 30m loops). Event schema
and a consumer example: docs/notificacoes.mdx.
Keyring-first, env-second. Never commit credentials, cookies, downloaded live HTML, SQLite databases, exported PDFs, or .env files.
sigaa init stores your SIGAA password securely in your OS keyring and verifies the login. Public SIPAC queries do not need credentials.
After sigaa login, no environment variables are needed. For headless
environments without a keyring: export SIGAA_USER=username SIGAA_PASS=password
(plaintext password files are not recommended). Optional: SIGAA_DB=/path/to/sigaa.db to override the store location.
Usually you should run sigaa init. The examples below are for manual setups,
debugging, or custom automation.
Run with sigaa-mcp (stdio). Wire into Claude Code via .mcp.json:
{
"mcpServers": {
"sigaa": {
"command": "uvx",
"args": [
"--from",
"sigaa-tools[mcp] @ git+https://github.com/PucaVaz/sigaa-tools",
"sigaa-mcp"
]
}
}
}This form carries no machine-specific path, so the file stays valid when
committed and shared with your team. sigaa init writes it for you. The server
reads the active account from your keyring; add
"env": { "SIGAA_USER": "your_user" } only if keyring is unavailable.
macOS (launchd) - sync every 30 min. Save as
~/Library/LaunchAgents/ai.sigaa.sync.plist then
launchctl load it:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"><dict>
<key>Label</key><string>ai.sigaa.sync</string>
<key>ProgramArguments</key>
<array>
<string>/Users/you/.local/bin/sigaa</string>
<string>sync</string>
</array>
<key>EnvironmentVariables</key>
<dict><key>SIGAA_USER</key><string>your_user</string></dict>
<key>StartInterval</key><integer>1800</integer>
</dict></plist>uv tool install puts sigaa in ~/.local/bin; launchd needs it spelled out in
full, since it does not expand ~. Run which sigaa to confirm yours.
Linux (cron): */30 * * * * $HOME/.local/bin/sigaa watch --once --bodies --jsonl --fail-on-error
(account and password from sigaa login; SIGAA_USER/SIGAA_PASS only where no keyring is reachable).
sigaa/
config.py endpoints, JSF constants, slot-time table, creds resolution
http.py session: cookie jar, ViewState, re-login + retry
auth.py login flow
client.py SigaaClient -> domain models
sipac.py unauthenticated public SIPAC process client + JSON contract
models.py Student, Turma, NewsItem, Schedule, CurriculumStatus
parsers/ portal, news, schedule, curriculum, transcript, extensão, SIPAC process
store/ SQLite db + repository (dedup, queries)
services/ sync (fetch -> diff -> persist)
cli.py command line
mcp_server.py agent tools
Adding a feature (materials, attendance) = a parser + client method and a
CLI/MCP surface, plus store columns when it is persisted. HTML changes touch
only parsers/. Implemented so far: classes, news (+bodies), grades, deadlines,
curriculum progress, official CRA, academic documents, extension
participations, and ICS export.
Public SIPAC administrative-process consultation is also available live.
exporters/ turns store data into interchange formats (currently ics).
6M2345 → Fri (day 6) morning slots 2–5. Days 2=Mon..7=Sat, shift M/T/N.
Clock times in config.SLOT_TIMES_UNCONFIRMED are an unconfirmed default —
verify against a turma's "Plano de Curso" before using them for calendar export.
pytest # offline: parsers run on fixtures, store on in-memory sqliteInterested in hacking on sigaa-tools? See CONTRIBUTING.md for setup and release instructions.
Single-user, local-first tool. config.py reads credentials from keyring first
and environment variables second. The SQLite db is local and may contain student
data copied from SIGAA. .gitignore excludes *.db, .env, and live HTML
dumps, but review generated files before sharing logs, issues, or screenshots.
The SIPAC process feature is read-only and public; it does not send stored
credentials, but its responses can contain names and identifiers already shown
by the public portal, so handle exported JSON responsibly.
MIT. See LICENSE.