# Installing ASU Canvas Course Builder in Codex

This guide walks you through installing the plugin in **Codex** (OpenAI's CLI agent). It is written for non-technical users — every step is spelled out, and every command can be copy-pasted.

If you get stuck, send the person who shared the plugin with you the exact error text you see. Don't guess.

You can do this two ways:

- **Hands-off (recommended for non-technical users):** open Codex, attach this guide, and say *"I want to set up the ASUCB plugin on Codex. Follow this guide."* Codex runs the steps for you. See **For a Codex agent running this guide** below.
- **By hand:** follow Steps 1–5 yourself in the Terminal.

---

## For a Codex agent running this guide

If you are a Codex agent executing this guide for a user, follow these rules — do not just echo the commands literally:

1. **Resolve placeholders from the real system.** Where the guide says `THE-NAME-YOU-SAW`, actually run `ls ~/Downloads` and `ls ~/plugins`, read the output, and use the real filename. Where it says `asu-canvas-builder.zip`, find the actual zip the user downloaded (look in `~/Downloads` for the most recent `*canvas*builder*.zip`). Never paste a literal placeholder into a command.
2. **Run every "Verify" command** and read its output before moving on. If a verify fails, stop and fix that step — do not continue.
3. **Never overwrite an existing `~/.agents/plugins/marketplace.json`.** If the file already exists, read it, and *merge* the `canvas-builder` plugin object into its existing `"plugins"` array (preserving other entries). Only use the `cat > … <<'EOF'` create command when the file does not exist.
4. **Python is auto-installed — do not ask the user to install it.** Step 3 runs `hooks/ensure_deps.sh`, which detects whether Python 3.9+ is present and, if not, installs `uv` and a managed Python 3.12 into a plugin-local virtualenv automatically. Just run the script and report the result. The plugin's hook files ship inside the plugin folder — there is nothing separate to "install" for hooks.
5. **Ask the user for their Canvas token + domain (Step 5) and write the `.env` file for them.** You cannot generate the token — walk the user through generating it in Canvas, then ask them to paste it. Handle it securely: do not echo the token back, do not write it to logs, chat, or any file other than `.env`. See Step 5.
6. **Stop and hand back to the user at two points you cannot do yourself:**
   - Restarting Codex (Step 4) — you cannot restart the process you are running in. Finish Steps 1–3, then tell the user to fully quit and reopen Codex, then enable the plugin.
   - Generating the Canvas token (Step 5) — only the user can do this in their Canvas account.
7. **Report a clear summary at the end:** what succeeded, what the user must still do (restart Codex, enable the plugin), and any verify command that failed.

---

## What you are about to do

The plugin is a folder of files. To make Codex *use* it, three things have to be true:

1. The plugin folder lives at a known location on your computer.
2. A small settings file tells Codex "there is a plugin here."
3. The plugin's Python dependencies are installed.

That's the whole install. The steps below do exactly those three things.

---

## Before you start — checklist

You need all three of these. Get them ready before you begin:

- [ ] **Codex CLI installed.** Open the Terminal app and run:
  ```bash
  codex --version
  ```
  If you see a version number (e.g. `codex-cli 0.129.0`), you're good. If you see `command not found`, install Codex first — ask your team how, then come back.

- [ ] **The plugin zip.** Open the team's Coda doc, go to the **"Download & Versions"** page, and download the `.zip` attached at the bottom of that page. (The plugin repo is private — the Coda attachment is how IDs and IDAs get the plugin.) Have the zip in your `Downloads` folder.

- [ ] **A Canvas API token.** You will create this yourself later (Step 5) — never accept a token from someone else, and never share yours. Just know it's coming.

> **About the Terminal:** every command block below is run in the macOS **Terminal** app (press `Cmd+Space`, type "Terminal", press Enter). Copy a block, paste it, press Enter. Run them one at a time, top to bottom.

---

## Step 1 — Put the plugin folder in the right place

Codex will look for the plugin at `~/plugins/canvas-builder`. (`~` means your home folder, e.g. `/Users/yourname`.)

First, create the `plugins` folder:

```bash
mkdir -p ~/plugins
```

`mkdir -p` means "make this folder; do nothing if it already exists." Safe to run either way.

Now put the plugin **inside** that folder, named exactly `canvas-builder`.

**If you were given a `.zip` file:**

```bash
unzip ~/Downloads/asu-canvas-builder.zip -d ~/plugins/
```

Then check what the unzip created and rename it if needed so the final path is exactly `~/plugins/canvas-builder`:

```bash
ls ~/plugins
```

If you see a folder with a different name (e.g. `asu-canvas-builder` or `ASU Canvas Builder`), rename it:

```bash
mv "~/plugins/THE-NAME-YOU-SAW" ~/plugins/canvas-builder
```

(Replace `THE-NAME-YOU-SAW` with the actual name from the `ls` output. Keep the quotes if the name has spaces.)

**If you were given a git repo to clone**, your team will give you the clone command — clone it directly to the right place:

```bash
git clone <repo-url> ~/plugins/canvas-builder
```

**Verify Step 1.** This must show files, not an error:

```bash
ls ~/plugins/canvas-builder
```

You should see folders like `skills`, `scripts`, `hooks`, `.codex-plugin`, and files like `README.md`. If you see `No such file or directory`, the folder isn't named or placed right — fix it before continuing.

---

## Step 2 — Tell Codex the plugin exists

Codex reads a settings file called a **marketplace file**. It's a short text file that lists plugins. You'll create it.

Create the folder it lives in:

```bash
mkdir -p ~/.agents/plugins
```

Now create the marketplace file. **Copy this entire block and paste it into the Terminal as one piece**, then press Enter:

```bash
cat > ~/.agents/plugins/marketplace.json <<'EOF'
{
  "name": "personal",
  "interface": {
    "displayName": "Personal"
  },
  "plugins": [
    {
      "name": "canvas-builder",
      "source": {
        "source": "local",
        "path": "./plugins/canvas-builder"
      },
      "policy": {
        "installation": "AVAILABLE",
        "authentication": "ON_INSTALL"
      },
      "category": "Productivity"
    }
  ]
}
EOF
```

This writes the whole file in one go. What it says, in plain English: "There is a marketplace called *Personal*. It contains one plugin, *canvas-builder*, located at `~/plugins/canvas-builder`."

> **Important:** the file must be the **complete** block above — the outer `{ "name": "personal", ... "plugins": [ ... ] }` wrapper included. A file containing only the inner plugin object is **invalid** and Codex will ignore it.

> **If `~/.agents/plugins/marketplace.json` already exists** with other plugins in it, do NOT overwrite it — the command above would erase the others. Instead, open the existing file and add just the `canvas-builder` object (the inner block, from `{ "name": "canvas-builder"` to its closing `}`) into the existing `"plugins": [ ... ]` list, separated from other entries by a comma. If you're not comfortable editing JSON by hand, ask your team to do this part.

**Verify Step 2.** This must print the file's contents with no error:

```bash
cat ~/.agents/plugins/marketplace.json
```

---

## Step 3 — Install the plugin's dependencies

The plugin needs a few Python packages. One command installs them:

```bash
bash ~/plugins/canvas-builder/hooks/ensure_deps.sh
```

This takes a minute or two the first time. **You do not need Python installed beforehand.** The script checks for Python 3.9+ and, if it's missing, automatically installs `uv` (a small Python installer) and a managed Python 3.12 into a private folder just for the plugin. It also wires up the plugin's hooks. Nothing for you to install by hand. When it finishes you'll get your Terminal prompt back.

If it prints errors, the detailed log is saved at `/tmp/asucb-pip.log` — send that to your team.

---

## Step 4 — Restart Codex and open the plugin

1. Fully quit Codex (not just close the window).
2. Start Codex again.
3. Open the Codex plugin UI / plugin list. **ASU Canvas Course Builder** should appear under the *Personal* marketplace.
4. Install / enable it.

---

## Step 5 — Connect your Canvas account

The plugin needs two things to talk to Canvas: your **Canvas API token** and your **Canvas domain**. They are stored once in a private file (`.env`) inside the plugin folder — git-ignored, never shared, never asked again.

### Generate your Canvas token

You must create the token yourself — no one can do this for you, and you should never accept a token from anyone else:

1. In a browser, go to Canvas → click your **Account** → **Settings**.
2. Scroll to **Approved Integrations** → **+ New Access Token**.
3. Give it a name (e.g. "ASUCB"), leave the expiry blank or set one, click **Generate Token**.
4. Copy the token. **Treat it like a password** — never paste it into a chat, email, Slack, or share it with anyone.

### Save the token

When you have the token, the plugin asks for it the first time you do anything Canvas-related — paste it in, and give your domain (`canvas.asu.edu` for ASU). That's it.

> **For a Codex agent running this guide:** at this step, ask the user directly — *"Paste your Canvas API token, and tell me your Canvas domain (default: `canvas.asu.edu`)."* When they answer, write the file `~/plugins/canvas-builder/.env` with exactly these two lines (no quotes, no extra spaces):
>
> ```
> CANVAS_TOKEN=<the token the user pasted>
> CANVAS_DOMAIN=canvas.asu.edu
> ```
>
> Security rules for the agent: do **not** echo the token back in your reply, do **not** write it to logs, chat history, a commit, or any file other than `.env`. `.env` is git-ignored by design — that is the only correct place for it. After writing the file, confirm only *"Canvas credentials saved to .env"* — never repeat the token value.

---

## Did it work?

In Codex, type `/` and look for `course-concierge` in the skill list, or just say:

> "Help me build an ASU Canvas course."

If the plugin responds and starts guiding you, the install succeeded.

---

## Troubleshooting

| Symptom | Fix |
|---|---|
| Plugin doesn't appear in Codex | Re-check Step 2 — the marketplace file must be the full block with the `"name": "personal"` wrapper. Run `cat ~/.agents/plugins/marketplace.json` and compare. Then fully restart Codex. |
| `ls ~/plugins/canvas-builder` says "No such file or directory" | The folder isn't placed/named right. The path must be exactly `~/plugins/canvas-builder`. Redo Step 1. |
| `ensure_deps.sh` errors | Send `/tmp/asucb-pip.log` (and `/tmp/asucb-uv-install.log` if it exists) to your team. |
| `codex: command not found` | Codex CLI isn't installed. Install it first. |
| Plugin loads but Canvas calls fail | Your Canvas token may be wrong or expired. Generate a fresh one (Step 5). |

---

## For maintainers — developing the plugin and running it in Codex

If you are a developer and the plugin repo lives somewhere other than `~/plugins/canvas-builder` (for example a working copy on your Desktop), you do **not** need a second copy. Point Codex at your working copy with a symlink:

```bash
mkdir -p ~/plugins
ln -s "/path/to/your/repo" ~/plugins/canvas-builder
```

The marketplace file from Step 2 is unchanged — `~/plugins/canvas-builder` now redirects to your real repo, so both Codex and your editor work on one source tree.

The plugin scripts resolve their root from `ASUCB_PLUGIN_ROOT`, then `CODEX_PLUGIN_ROOT`, then `CLAUDE_PLUGIN_ROOT`. If you run a script by hand outside Codex, export the root first:

```bash
export ASUCB_PLUGIN_ROOT="$HOME/plugins/canvas-builder"
```

---

## Updating to a new version

When a new release ships, you update by **replacing the plugin folder** — there is no auto-update, and the plugin repo is private so there is nothing to `git pull`.

1. **Get the new zip.** Open the **"Download & Versions"** page in the team's Coda doc. The latest release `.zip` is attached at the bottom of that page — download it.
2. **Replace the old folder.** Delete the current plugin folder and put the new one in its place, keeping the exact same path:
   ```bash
   rm -rf ~/plugins/canvas-builder
   unzip ~/Downloads/asu-canvas-builder.zip -d ~/plugins/
   ```
   (Rename the unzipped folder to `canvas-builder` if needed — see Step 1 of the install.)
3. **Re-run the dependency script** — a new release may add Python packages:
   ```bash
   bash ~/plugins/canvas-builder/hooks/ensure_deps.sh
   ```
4. **Restart Codex.**

Your Canvas credentials (`.env`) are **not** inside the zip — they live in the plugin folder and are recreated per machine. If you `rm -rf` the folder, you will re-enter your token once on next use (Step 5). To keep it, copy `.env` out first and back in after:
```bash
cp ~/plugins/canvas-builder/.env ~/asucb-env-backup    # before replacing
cp ~/asucb-env-backup ~/plugins/canvas-builder/.env     # after replacing
```

> **For a Codex agent running an update:** do the same — back up `.env`, replace the folder, run `ensure_deps.sh`, then tell the user to restart Codex. Never delete `.env` without backing it up first.

---

## Claude Code compatibility

The plugin is dual-runtime. Claude Code uses `.claude-plugin/plugin.json` + `hooks/hooks.json`; Codex uses `.codex-plugin/plugin.json`. Both manifests point at the same `skills/`, `scripts/`, `templates/`, and `standards/` directories — one source tree, two runtimes.

Do not remove or rename: `.claude-plugin/plugin.json`, `.codex-plugin/plugin.json`, `hooks/hooks.json`, `hooks/ensure_deps.sh`, `skills/`, `scripts/`, `templates/`, `standards/`.

The two manifests' `version` fields must always match — `tests/test_plugin_manifest_sync.py` enforces this.

---

## Rollback — remove Codex support

To remove the Codex install without affecting Claude Code:

1. Remove the `canvas-builder` entry from `~/.agents/plugins/marketplace.json` (or delete the file if it only contains that one plugin).
2. Delete `~/plugins/canvas-builder` (the folder, or the symlink if you used one).
3. Restart Codex.

`.claude-plugin/` and `hooks/` are untouched — Claude Code keeps working.
