> ## Documentation Index
> Fetch the complete documentation index at: https://docs.pawtograder.com/llms.txt
> Use this file to discover all available pages before exploring further.

# CLI Interface

> Command-line tools for managing courses, assignments, rubrics, and student repositories

# Pawtograder CLI (Beta)

The Pawtograder CLI provides command-line tools for instructors and site administrators to manage courses, copy assignments between semesters, import rubrics and submission data, and perform bulk repository operations.

<Warning>
  The CLI is in beta. Commands and options may change in future releases.
</Warning>

## Installation

The CLI ships inside the platform repository and runs via npm scripts. Run it from the repository root:

```bash theme={null}
npm run cli -- <command> [options]
```

For repository commands, use the shortcut:

```bash theme={null}
npm run cli:repos -- <subcommand> [options]
```

### Prerequisites

* Node.js 18 or later
* SSH access to GitHub (for repository operations)
* A Pawtograder API token with CLI access

## Authentication

Before using the CLI, authenticate with an API token.

### Creating an API token

1. Log in to the Pawtograder web app.
2. Navigate to **User Menu → API Tokens**.
3. Create a new token with type **"CLI"** or **"MCP + CLI"**.
4. Copy the token. It starts with `mcp_`.

### Logging in

```bash theme={null}
npm run cli -- login
```

You'll be prompted to enter your API token. The token is stored securely in `~/.pawtograder/credentials.json`.

You can also provide the token directly:

```bash theme={null}
npm run cli -- login --token mcp_your_token_here
```

For custom deployments, specify the API URL:

```bash theme={null}
npm run cli -- login --url https://your-instance.com/functions/v1/cli
```

### Checking authentication

```bash theme={null}
npm run cli -- whoami
```

### Logging out

```bash theme={null}
npm run cli -- logout
```

## Commands

### Classes

List all classes you have access to:

```bash theme={null}
npm run cli -- classes list
```

Show details for a specific class:

```bash theme={null}
npm run cli -- classes show <class-id-or-slug>
```

The identifier can be a class ID, slug, or name.

### Assignments

List assignments for a class:

```bash theme={null}
npm run cli -- assignments list --class <class-id-or-slug>
```

Show assignment details:

```bash theme={null}
npm run cli -- assignments show <assignment-id-or-slug> --class <class-id-or-slug>
```

#### Copy assignments

Copy assignments between classes. Supports single-assignment copy, full-course copy, and schedule-driven copy:

```bash theme={null}
# Copy a single assignment
npm run cli -- assignments copy \
  --source-class cs3500-fall-2025 \
  --target-class cs3500-spring-2026 \
  --assignment hw1 \
  --workdir /tmp/pawtograder-repos

# Copy all assignments
npm run cli -- assignments copy \
  --source-class cs3500-fall-2025 \
  --target-class cs3500-spring-2026 \
  --all \
  --workdir /tmp/pawtograder-repos

# Copy with a schedule CSV (custom due dates)
npm run cli -- assignments copy \
  --source-class cs3500-fall-2025 \
  --target-class cs3500-spring-2026 \
  --schedule schedule.csv \
  --workdir /tmp/pawtograder-repos
```

The copy command handles:

* Assignment record creation
* Rubrics (deep copy)
* Autograder configuration
* Self-review settings
* Handout and solution repository content (via local SSH git)

`--workdir` is required for repository content copying. The CLI uses local SSH git operations to avoid Supabase timeout limits.

**Options:**

| Option           | Description                                                     |
| ---------------- | --------------------------------------------------------------- |
| `--source-class` | Source class (ID, slug, or name)                                |
| `--target-class` | Target class (ID, slug, or name)                                |
| `--assignment`   | Single assignment to copy (ID or slug)                          |
| `--schedule`     | CSV file with assignment slugs/titles and date overrides        |
| `--all`          | Copy all assignments from the source class                      |
| `--workdir`      | Local directory for git clones (required unless `--skip-repos`) |
| `--dry-run`      | Preview changes without making them                             |
| `--skip-repos`   | Skip git repository operations                                  |
| `--skip-rubrics` | Skip rubric copying                                             |
| `--skip-surveys` | Skip copying surveys linked to assignments                      |
| `--concurrency`  | Parallel clone/fetch operations (1-8, default 4)                |
| `--delay-ms`     | Delay between clone batches in milliseconds                     |
| `--debug`        | Enable server-side timing logs                                  |

#### Schedule file format

Create a CSV with assignment slugs and new due dates:

```csv theme={null}
slug,due_date
hw-01,2026-09-15T23:59:00
hw-02,2026-09-22T23:59:00
project-01,2026-10-01T23:59:00
```

#### Delete an assignment

```bash theme={null}
npm run cli -- assignments delete <assignment-id-or-slug> --class <class-id-or-slug>
```

Add `--force` to skip the confirmation prompt.

### Rubrics

Import and export rubrics in YAML format.

List rubrics for an assignment:

```bash theme={null}
npm run cli -- rubrics list \
  --assignment <assignment-id-or-slug> \
  --class <class-id-or-slug>
```

Export a rubric to YAML:

```bash theme={null}
npm run cli -- rubrics export \
  --assignment hw1 \
  --class cs3500-spring-2026 \
  --type grading \
  --output hw1-rubric.yml
```

Import a rubric from YAML:

```bash theme={null}
npm run cli -- rubrics import \
  --assignment hw1 \
  --class cs3500-spring-2026 \
  --file hw1-rubric.yml \
  --type grading
```

Use `--dry-run` to preview the import without making changes.

### Surveys

Copy surveys between classes:

```bash theme={null}
# Copy a single survey
npm run cli -- surveys copy \
  --source-class cs3500-fall-2025 \
  --target-class cs3500-spring-2026 \
  --survey "Midterm Feedback"

# Copy all surveys
npm run cli -- surveys copy \
  --source-class cs3500-fall-2025 \
  --target-class cs3500-spring-2026 \
  --all

# Link copied survey to a target assignment
npm run cli -- surveys copy \
  --source-class cs3500-fall-2025 \
  --target-class cs3500-spring-2026 \
  --survey "HW1 Reflection" \
  --target-assignment hw1
```

List surveys for a class:

```bash theme={null}
npm run cli -- surveys list --class cs3500-fall-2025
```

### Flashcards

List flashcard decks:

```bash theme={null}
npm run cli -- flashcards list --class <class-id-or-slug>
```

Copy flashcard decks between classes:

```bash theme={null}
npm run cli -- flashcards copy \
  --source-class cs3500-fall-2025 \
  --target-class cs3500-spring-2026 \
  --all
```

### Submissions

List submissions for an assignment:

```bash theme={null}
npm run cli -- submissions list \
  --class cs3500-fall-2025 \
  --assignment hw1
```

#### Import or sync comments

Batch import submission comments from autograder results:

```bash theme={null}
# Add-only import
npm run cli -- submissions comments import \
  --class cs3500-spring-2026 \
  --assignment hw1 \
  --file batch-results.json \
  --author-profile-id <uuid>

# Sync (insert new + soft-delete missing)
npm run cli -- submissions comments sync \
  --class cs3500-spring-2026 \
  --assignment hw1 \
  --file batch-results.json \
  --rubric-part-id <id>
```

Use `--rubric-part-id` instead of `--author-profile-id` to attribute comments to review assignment assignees.

#### Import artifacts

Upload submission artifact blobs from a manifest:

```bash theme={null}
npm run cli -- submissions artifacts import \
  --class cs3500-spring-2026 \
  --assignment hw1 \
  --file manifest.json \
  --batch-size 5
```

**Options:**

* `--overwrite` – Replace existing artifacts with the same name
* `--dry-run` – Preview counts only
* `--batch-size <n>` – Artifacts per API request (default 5)

The manifest is a JSON file with this structure:

```json theme={null}
{
  "artifacts": [
    {
      "submission_id": 123,
      "name": "coverage-report",
      "data": {
        "format": "html",
        "display": "Coverage Report"
      },
      "content_base64": "PGh0bWw+Li4uPC9odG1sPg=="
    }
  ]
}
```

You can use `content_file` instead of `content_base64` to reference an external file:

```json theme={null}
{
  "submission_id": 123,
  "name": "coverage-report",
  "data": { "format": "html", "display": "Coverage Report" },
  "content_file": "./reports/coverage-123.html"
}
```

### Help requests

List office hours help requests:

```bash theme={null}
npm run cli -- help-requests list --class cs3500-fall-2025
```

### Discussions

List discussion board threads:

```bash theme={null}
npm run cli -- discussions list --class cs3500-fall-2025
```

### Reviews

List peer and grading review assignments:

```bash theme={null}
npm run cli -- reviews list \
  --class cs3500-fall-2025 \
  --assignment hw1
```

## Repository operations

Repository commands use local SSH git operations for reliability and performance.

<Warning>
  Repository commands require SSH access to GitHub. Ensure your SSH keys are configured and you have access to the course organization.
</Warning>

### List repositories

```bash theme={null}
npm run cli:repos -- list --class <class-id-or-slug> --assignment <assignment-id-or-slug>
```

### Sync grade workflow

Synchronize `.github/workflows/grade.yml` from the handout repository to all student repositories:

```bash theme={null}
npm run cli:repos -- sync-grade-workflow \
  --class cs3500-spring-2026 \
  --assignment hw1 \
  --workdir /tmp/pawtograder-repos \
  --concurrency 2
```

This command:

1. Fetches the canonical `.github/workflows/grade.yml` from the handout repository.
2. Clones all student repositories locally via SSH.
3. Updates the workflow file in each repository.
4. Commits and pushes changes.

**Options:**

* `--dry-run` – Preview which repos would be updated
* `--concurrency <n>` – Parallel git operations (1-8, default 2)
* `--delay-ms <n>` – Delay between clone batches

### Cross-assignment copy

Copy files from source assignment repositories to target assignment repositories after the source due date. This is useful for sequential assignments where students build on previous work:

```bash theme={null}
npm run cli:repos -- copy-after-source-due \
  --class cs3500-spring-2026 \
  --source-assignment hw1 \
  --target-assignment hw2 \
  --workdir /tmp/pawtograder-repos \
  --concurrency 2
```

The CLI:

1. Verifies the source assignment due date has passed.
2. Clones source and target repositories for each student or group.
3. Copies files using rsync (excluding `.git`).
4. Commits and pushes to target repositories.

**Options:**

* `--dry-run` – Preview with `rsync -n` only
* `--mirror-delete` – Pass `rsync --delete` (still excludes `.git`)
* `--concurrency <n>` – Parallel operations (1-8, default 2)
* `--delay-ms <n>` – Delay between batches

## Common options

Most commands support these options:

* `--dry-run` – Preview changes without making them
* `--help` – Show command-specific help
* `--class` or `-c` – Specify a class by ID, slug, or name
* `--assignment` or `-a` – Specify an assignment by ID or slug

## Environment variables

| Variable                      | Description                                                                              |
| ----------------------------- | ---------------------------------------------------------------------------------------- |
| `PAWTOGRADER_HTTP_TIMEOUT_MS` | HTTP request timeout in milliseconds. Set to `600000` (10 minutes) for large operations. |
| `DEBUG`                       | Set to `1` to enable verbose HTTP logging.                                               |

```bash theme={null}
export PAWTOGRADER_HTTP_TIMEOUT_MS=600000
export DEBUG=1
npm run cli -- <command>
```

## API token scopes

CLI tokens require specific scopes:

* `cli:read` – Read-only operations (list, show, export)
* `cli:write` – Write operations (copy, import, delete)

Create tokens with appropriate scopes in the web UI under **User Menu → API Tokens**.

## Common workflows

### Semester rollover

Copy an entire course to a new semester:

```bash theme={null}
# 1. Copy all assignments with new dates
npm run cli -- assignments copy \
  --source-class cs3500-fall-2025 \
  --target-class cs3500-spring-2026 \
  --schedule spring-2026-schedule.csv \
  --workdir ./repos

# 2. Copy surveys
npm run cli -- surveys copy \
  --source-class cs3500-fall-2025 \
  --target-class cs3500-spring-2026 \
  --all

# 3. Copy flashcards
npm run cli -- flashcards copy \
  --source-class cs3500-fall-2025 \
  --target-class cs3500-spring-2026 \
  --all
```

### Bulk rubric updates

```bash theme={null}
# 1. Export the current rubric
npm run cli -- rubrics export \
  --assignment hw1 \
  --class cs3500-spring-2026 \
  --output hw1-rubric.yml

# 2. Edit hw1-rubric.yml locally

# 3. Preview changes
npm run cli -- rubrics import \
  --assignment hw1 \
  --class cs3500-spring-2026 \
  --file hw1-rubric.yml \
  --dry-run

# 4. Apply changes
npm run cli -- rubrics import \
  --assignment hw1 \
  --class cs3500-spring-2026 \
  --file hw1-rubric.yml
```

### Repository maintenance

```bash theme={null}
# Update grade workflows across all student repos
npm run cli:repos -- sync-grade-workflow \
  --class cs3500-spring-2026 \
  --assignment hw1 \
  --workdir ./repos \
  --dry-run

# Copy starter code from hw1 to hw2 after hw1 due date
npm run cli:repos -- copy-after-source-due \
  --class cs3500-spring-2026 \
  --source-assignment hw1 \
  --target-assignment hw2 \
  --workdir ./repos \
  --dry-run
```

## Best practices

1. **Use dry-run first.** Preview changes with `--dry-run` before executing.
2. **Export backups.** Export rubrics before importing new versions.
3. **Batch size.** For artifact imports, reduce `--batch-size` if requests time out.
4. **Dedicated workdir.** Use a dedicated directory for `--workdir` to avoid conflicts.
5. **Concurrency.** Start with the default and adjust based on network performance.

## Troubleshooting

### Authentication errors

If you see "Not logged in" or "Authentication failed":

1. Run `npm run cli -- login` to re-authenticate.
2. Verify your token is valid in the web UI (**User Menu → API Tokens**).
3. Ensure your token has the correct scopes (`cli:read` or `cli:write`).

Common HTTP errors:

* **401 Unauthorized** – Token expired or revoked. Log in again.
* **403 Forbidden** – Token lacks required scopes.
* **504 Gateway Timeout** – Operation took too long. Increase the timeout or use smaller batches.

### Command not found

Run the CLI from the platform repository root and make sure dependencies are installed with `npm install`.

### Timeout errors

For large operations (copying many assignments, importing large artifacts):

1. Set a longer timeout: `PAWTOGRADER_HTTP_TIMEOUT_MS=600000 npm run cli -- ...`
2. Use smaller batch sizes (for example, `--batch-size 1` for artifact imports).
3. Use `--dry-run` first to validate before running the full operation.

For assignment copy operations, the CLI validates and fixes existing assignments on retry, so you can safely re-run failed commands.

### Repository clone failures

If SSH git operations fail:

1. Verify SSH keys are configured: `ssh -T git@github.com`
2. Check that you're a member of the course's GitHub organization.
3. Retry with lower `--concurrency` (try 2 or 1).
4. Use `--delay-ms 1000` to add delays between batches.

### Connection reset errors

The CLI automatically retries git operations that fail due to connection resets. If failures persist:

1. Check your network connection.
2. Verify GitHub is accessible.
3. Reduce `--concurrency` to avoid rate limits.

## Getting help

For detailed help on any command:

```bash theme={null}
npm run cli -- <command> --help
```

For example:

```bash theme={null}
npm run cli -- assignments --help
npm run cli -- assignments copy --help
```
