Metadata-Version: 2.4
Name: grabdeeznust
Version: 0.1.1
Summary: MCP server + CLI (gdn) that lets any agent harness submit a NUST LMS lab by harvesting another account's submission and re-skinning it under the user's identity.
License: MIT
Project-URL: Homepage, https://github.com/ZaynIkhlaq/grabdeeznust
Project-URL: Repository, https://github.com/ZaynIkhlaq/grabdeeznust
Project-URL: Issues, https://github.com/ZaynIkhlaq/grabdeeznust/issues
Keywords: mcp,playwright,lms,moodle,claude-code,opencode,nust,grabdeeznust,gdn
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: End Users/Desktop
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Education
Requires-Python: >=3.11
Description-Content-Type: text/markdown
Requires-Dist: playwright>=1.48.0
Requires-Dist: python-docx>=1.1.2
Requires-Dist: pdfplumber>=0.11.0
Requires-Dist: python-dotenv>=1.0.1
Requires-Dist: mcp>=1.27.0

# grabdeeznust

**`gdn`** for short. MCP server + CLI that lets any agent harness submit a NUST LMS lab by harvesting a friend's already-submitted work and re-skinning it under the user's own identity.

The "agent" is whatever LLM is driving the harness — Claude Code, OpenCode, Cursor, Cline, Continue, Zed, the Anthropic SDK, etc. `grabdeeznust` only provides the deterministic plumbing: log into the LMS, download submitted files, re-render a styled report.docx, log back in as the user and upload it.

Two LMS accounts are involved:

- **Account 1** — the user's own account; submissions are uploaded here
- **Account 2** — a friend's account; their already-submitted files are harvested here

NUST LMS assignment URLs are the same on both accounts, so the user supplies the URL once and the tool reuses it.

## Install

```bash
pipx install grabdeeznust
gdn setup
```

`gdn setup` walks you through a one-time onboarding:

1. Prompts for both LMS account credentials (passwords are hidden).
2. Prompts for the identity values (`IDENTITY_NAME`, `IDENTITY_ROLL`, `IDENTITY_TERMINAL`) that get stamped into every report.
3. Saves it all to `~/.gdn/.env` with mode 0600.
4. Downloads Playwright's Chromium (~150 MB, one-time).
5. Prints the MCP config block to paste into your agent harness.

Run `gdn doctor` any time to check that everything's still in place.

### From source (dev)

```bash
git clone https://github.com/ZaynIkhlaq/grabdeeznust
cd grabdeeznust
uv sync
uv run gdn setup
```

A `.env` in the repo root takes precedence over `~/.gdn/.env`, so dev work doesn't pollute your real config.

## Use it as an MCP server (recommended)

Add one block to your harness's MCP config.

**Claude Code** (`~/.claude/mcp.json` or per-project `.mcp.json`):

```json
{
  "mcpServers": {
    "gdn": {
      "command": "gdn",
      "args": ["mcp"]
    }
  }
}
```

Or via the CLI: `claude mcp add gdn -- gdn mcp`.

**OpenCode**, **Cursor**, **Cline**, **Continue**, **Zed**, **Claude Desktop** — same shape, in their respective MCP settings file. Any MCP-aware client works.

The agent now has these tools:

| Tool | Purpose |
|---|---|
| `gdn_harvest(url)` | Login as account 2, download every submitted file at URL |
| `gdn_extract(source_path)` | Dump docx/pdf/zip/code as plain text |
| `gdn_render(plan, out_path)` | Render plan dict → styled docx (auto-verified) |
| `gdn_verify(docx_path)` | Identity check on an existing docx |
| `gdn_submit(url, files)` | Login as account 1, remove old draft, upload files |

And these resources for the agent to fetch context:

- `gdn://briefing` — full operator briefing (CLAUDE.md content)
- `gdn://schema` — plan dict schema + tone rules (prompts/system.md)

## Use it as a plain CLI

If you'd rather drive each step manually:

```bash
gdn harvest <URL>                          # account 2 downloads files
gdn extract <source-file>                  # source → plain text
# write work/<slug>/plan.json (schema in prompts/system.md)
gdn render plan.json --out report.docx     # plan → styled docx + verify
gdn submit <URL> <file1> <file2> ...       # account 1 uploads
```

Browser is **visible by default** so you can watch. Pass `--headless` before the subcommand to hide it.

## How the report is generated

The browser side is fully deterministic. The "thinking" step — read the source, write a plan that re-skins the report under the user's identity in a student-tone voice — is performed by **the LLM driving the harness**, not by any baked-in API call. That keeps `grabdeeznust` provider-neutral: no Anthropic key, no OpenAI key, nothing to configure beyond the LMS creds and the identity values.

The plan is just a JSON dict matching the schema in `prompts/system.md`. The renderer is pure Python (python-docx) and styles the docx to match the format Claude.ai's web app produces:

- Arial 11pt body
- Courier New 9pt code blocks on dark `#1E1E2E` (the "fake terminal" look)
- Courier New 9pt output blocks on light green `#F0FFF0`
- Section headings (Introduction / Task N / Conclusion) bold 17pt with bottom rule
- Italic captions on light-blue `#EBF3FB` panel with a thin blue border

Anything that looks like an AI tell (`Claude`, `Anthropic`, `as an AI`, `language model`) trips the verifier and blocks render.

## Layout

```
agent.py             # CLI dispatcher
browser.py           # Playwright NUST LMS driver (selectors pinned at top)
report.py            # source extraction + docx rendering + verification
mcp_server.py        # FastMCP wrapper exposing the above as MCP tools/resources
prompts/system.md    # plan-schema + tone guide for whichever LLM is driving
CLAUDE.md            # operator briefing (read by Claude Code)
AGENTS.md            # pointer to CLAUDE.md (read by OpenCode and others)
work/<slug>/         # per-run scratch (source, plan.json, report.docx, error.png on failure)
```

## Notes

- Selectors live in one block at the top of `browser.py`. Tweak there if NUST LMS changes its DOM.
- "Screenshots" in the report are styled text captions ending in `(${IDENTITY_TERMINAL})`. No code execution, no real images.
- `GDN_WORK_DIR` env var overrides where `harvest` writes scratch files (default: `./work`).
