NRT Agentic AI Michigan State University

DEMO 10 · WEEK 4 IN CLASS — DESIGN AN AGENT, WRITE THE PLAN, SHIP IT TOGETHER

Design your own agent — and write the plan

Two hours, eight steps, one shared document. Bring a few papers, turn them into notes, then design an agent tool you actually want and write the implementation plan for it — cited, checked, and uploaded into a LaTeX project the whole room contributes to. No Zotero, no git, no LaTeX install.

Download Demo 10  ↓ ← Demo 9 The eight steps For the instructor All demos

This is the Week 4 in-class demo. Two hours, eight steps, one shared document at the end. No Zotero, no git, no LaTeX install — a folder, a browser, and Claude Code. The full research-writing system with a reference manager underneath is Demo 10x, and it is worth your time after Friday rather than before it.

The whole session on one page

Workflow diagram. Collect Papers (a PDF) feeds the Notes Agent, which writes notes/*.md. Collect a .bib file for anything you will cite. Then you talk your agent idea through with Claude, the Writing Agent drafts the plan in LaTeX or Markdown from notes, library, the web or you, producing a Draft report (.tex with cite keys), which goes to Overleaf writing in a push-compile-pull-revise loop. Collaborative: each person uploads groups/name.tex and the instructor assembles main.tex.
Eight steps. The first three are preparation, step 4 is the point, and the last four turn it into something twenty people can read.

The steps: 0 Setup · 1 Collect · 2 Notes · 3 Bib · 4 Design · 5 Draft · 6 Upload · 7 Assemble · 8 A skill of your own · For the instructor

What you leave with

A section of a real LaTeX document, in a project the whole room contributed to, describing an agent tool you actually want to build — with citations to the papers or documents you brought, and a list of the things you could not support.

Not a toy. The plan is the thing you would hand a collaborator, or give to Claude Code next week as the brief for building it.

sources/        whatever you collected — papers, decks, posts, SOPs, code
sources/notes/  one structured note per source
refs/refs.bib   the sources you will cite
writing/        myplan.tex — the deliverable
.claude/        three subagents, two skills, one permission boundary
IDEAS.md        starter questions for the part that matters
tools/          five Python tools that check things and fix nothing

0 · Setup — two minutes, in the room

cd Demo10_agent_design
python3 tools/doctor.py
python3 tools/snapshot.py

doctor.py needs python3 and Claude Code. It names everything else as optional and says why. You should see four ok lines under Core and nothing missing.

snapshot.py is the undo button: it zips your notes, refs and plan into .snapshots/ so an agent cannot lose work you wanted to keep, and --restore puts them back. Source PDFs are skipped — they are the one thing no agent will overwrite. That safety net is what makes it reasonable to let an agent write files at all.

There is no git in this package, and no shell scripts either. Every tool is Python, so Windows needs python3 and nothing else — no Git for Windows, no Git Bash, no WSL. The earlier draft of this demo required all three, for one reason: two of the five tools were .sh files. Porting them removed the requirement rather than documenting it. If you already use git, git init && git add -A && git commit is better than the snapshot and you should use that instead.

1 · Collect your sources — 10 min

cp ~/Downloads/*.pdf sources/

Not just papers. Anything that describes the work your agent would help with, or the problem it would solve:

whathow it gets in
papers, preprints.pdf — Claude reads these directly
slide decks.pptx, via tools/totext.py — or export to PDF
reports, SOPs, protocols.docx, .pdf, .md
blog posts, docs pagessave the page first — Print → Save as PDF
meeting notes, emails.md, .txt
a README or a scriptcode counts, and is often the most honest source you have

Two or three is plenty. This is not a literature review; you want enough that the tool you design has something concrete to be about.

Decks and Word files need one command

A .pptx or .docx is a zip of XML. pdftotext fails on one, nothing renders it, and strings finds nothing once the zip is compressed — so out of the box they are simply unreadable.

python3 tools/totext.py sources/deck.pptx      # slides + speaker notes
python3 tools/totext.py sources/report.docx
python3 tools/totext.py sources/post.html      # script, style, nav stripped

Standard library only, nothing to install. Verified against a real 62-slide deck: 62 slides and 62 speaker-note blocks out, in order. A deck that is entirely images extracts nothing — export it as PDF and let Claude read the pages.

Why you have to save a web page rather than paste the URL. The notes agent has no WebSearch and no WebFetch. Given a link, an agent that can browse will write a fluent, confident note from an abstract, a landing page, or a search result — and that note is indistinguishable from one written from the source. Saving the page takes five seconds and removes the whole failure mode. The cost is real and worth feeling: this is the capability layer working on you as well as for you. The writer agent does have web tools, because in a draft “found this online” is a legitimate tier that gets marked as such.

Nothing to hand? sources/README.md lists three real open-access papers (CC BY 4.0, you may cite them) that share one question and disagree about it.

sources/ is flat, on purpose. A document can be relevant to two things at once and a folder can only hold it in one place. The test before you ever add a subfolder: can one document belong to two of these at the same time? If yes, it is a field, not a folder — put it in the note's frontmatter and generate a view.

2 · Turn them into notes — 20 min

claude
/agents          # notes, writer, citecheck

Then once per document:

> Use the notes subagent on sources/<file>

It works out how to read the thing, writes sources/notes/<name>.md against a fixed eight-section template, sets kind: to what it actually is, and adds one row to sources/_index.md.

The template fits a blog post as well as a paper, and the sections that go thin are the point:

sectionfor a paperfor a launch post
## What it isa 2019 randomised triala vendor post — and who benefits from believing it
## Evidence given0.71 → 0.78 AUC, Table 2, n=418none — asserted, not shown
## Limitswhat the design cannot tell youusually the most useful section on the page

Writing “none — asserted, not shown” is a finding, not a hole in your note. check_notes.py only expects numbers in ## Evidence given when kind: is paper or preprint; it does fail on an empty one, whatever the kind.

It cannot fetch anything. Its tool list is Read, Write, Glob, Grep, Bash — no WebSearch, no WebFetch. If the document is not already in sources/ it says so and stops. That is deliberate: an agent that can browse will write a fluent, confident note from an abstract or a publisher blurb, and that note is indistinguishable from one written from the paper. Note that the writer agent does have web tools. The writer may browse; the filer may not.

Check it with a tool that repairs nothing

python3 tools/check_notes.py
sources/notes/Blog2026-why-we-stopped-notebooks.md ok 8 of 8 sections note doi: none — from https://example.com/why-we-stopped-... sources/notes/Deck2026-lab-automation.md ok 8 of 8 sections 2 note(s), 0 error(s), 0 warning(s)

It reports and fixes nothing, deliberately — a checker that edits is one that can make its own findings disappear. Two of its warnings are worth triggering on purpose so you see them:

WARN ## My take is not empty. If you wrote it, good. If an agent did, delete it — that section is yours. WARN ## Evidence given has no numbers and kind is paper. citecheck would have to reopen the source to do what this section is for. ERROR ## Evidence given is empty. If the source shows nothing, write: none — asserted, not shown

Then read one note like a reviewer

## My take is empty. It always is. No agent writes there. In six months it is the only section you can trust to be your own thinking.

## Problem and aim comes before ## Claim. A note that opens with the claim has already accepted the document's framing. What did they think was missing, and was the gap real?

## What it is is the provenance line, and it earns its place on the things that are not papers. A vendor post claiming a tool saves 40% is evidence of a claim, not of 40%.

## Relevance to my tool is the bridge to step 4. It is the agent's guess at why you collected this. Argue with it — the argument is most of what step 4 needs.

3 · A .bib entry for anything you will cite — 5 min

Only for real publications. Skip this entirely if your documents are internal; a plan with no citations is a fine plan.

Easiest route: on the paper's own page, find Cite or Export citation and choose BibTeX. Every major publisher has this.

No publisher page? Paste the DOI into doi2bib.org and copy what comes back.

Paste the entry into refs/refs.bib, then rename the cite key so it starts with your first name and a colon:

@article{alice:horne2012,          # was horne2012pharmacogenetic
  title  = {Pharmacogenetic warfarin dose refinements},
  year   = {2012},
  doi    = {10.1160/TH11-06-0388},
}

The prefix is not decoration. In step 6 twenty people paste into one shared refs.bib. Two identical cite keys make BibTeX fail, and the damage is not local:

Repeated entry---line 5 of file refs.bib latexmk exit 12 every citation in the document → (?) the References section → gone entirely

Measured here, not assumed. A .bbl is still written with the duplicate dropped, but latexmk stops before the pass that would use it — which is why the whole bibliography vanishes rather than losing one row. One person's collision breaks everybody's PDF.

The opposite failure is worth knowing too, because it is the quiet one: a cite key with no entry renders (?) for that one citation and latexmk exits 0. Nothing fails. You would find it at proof stage, or a reviewer would.

python3 tools/bibcheck.py

Duplicate keys across every file you give it, keys with no prefix, and entries with no DOI. Keep the doi field — it is the only identifier that survives moving between tools, and it is how citecheck joins your notes to your citations. Google Scholar's BibTeX export does not include one, which is why it is not the route recommended here.

4 · Design your agent, out loud, with Claude — 15 min

This is the part the rest of the session exists for. Everything before it is preparation; everything after it is write-up.

Open IDEAS.md for starter questions, then talk:

> Use the design skill. I want an agent that <describe the job>.

The skill is under instruction to ask you four questions and wait before proposing anything:

  1. What is the input, concretely? If the answer is abstract, it asks for a real example.
  2. What is the output, and how would you know it was wrong? If the answer is “I would read it carefully”, the design is not finished. What is the check?
  3. What must it never be able to do? Not should not — could not. That answer becomes a missing tool or a deny rule, not a sentence in a prompt.
  4. How often, and who else sees the output? Runs once → just ask. Runs weekly → a skill. Other people depend on it → the failure modes have to be written down.

Then it proposes, and the proposal has to place every rule in the lowest layer that can hold it:

layerwhere it liveswhat it is
contextCLAUDE.mda request. It can be misread, or forgotten the first time a fix looks obvious mid-task.
permission.claude/settings.jsona refusal. The call is blocked.
capabilitya subagent's tools: listan absence. There is nothing to call, so there is nothing to argue with.

If every rule in the proposal lands in “context”, say so and try again. That is the most common failure of a first design, and catching it here costs fifteen minutes instead of a term.

Starter questions, if the room goes quiet

Vague targets produce plans that read well and cannot be built. Push for the concrete version:

vagueconcrete
“help with my literature”“given a PDF, tell me whether its cohort overlaps a paper I already filed”
“clean my data”“given a plate-reader CSV, flag wells outside 3 SD and write a one-line log”
“help me write”“given a results table, draft the paragraph in my group's house style”

The skill ends by naming the one assumption that, if wrong, makes the whole design pointless, and how you could check it this week. Every design has one.

5 · Draft the implementation plan — 25 min

> Use the writer subagent: an implementation plan for the agent we just designed. LaTeX, into writing/myplan.tex. Cite anything from refs/refs.bib that supports a design choice.

Six subsections, and two of them are the ones people skip: Design, which must name the layer for each rule and say why not a weaker one, and How it can fail, which needs at least three failure modes each paired with the check that catches it. A plan with no failure modes has not been thought about.

What comes back marks where every claim came from:

markermeans
\cite{alice:horne2012}in refs/refs.bib, and there is a note saying you read it
% [UNREAD: key]the agent read the PDF just now. You have not.
% [WEB: url]found online, not in your refs. Not a citation yet.
% [GAP: …]nothing supports this. Say so rather than writing smoothly.

The last three are LaTeX comments, so they never typeset — but they stay in the source where you and anyone reading it can see them. Leave the gaps in. They are the plan telling you what you still have to find out, and \subsection{Open questions} is where they get promoted to prose. Deleting them so it reads finished is the one move that turns an honest plan into a confident wrong one.

A [WEB:] marker is settled by sending it round the loop again: decide the source is worth keeping, get its BibTeX, paste it into refs.bib with your prefix — and only then is it a real \cite{}. Free to write from anything; not free to cite anything.

Check the citations with an agent that cannot edit

> Use the citecheck subagent on writing/myplan.tex

It works cheapest-first: your notes, then the .bib as a lookup, and it opens a PDF only when those cannot settle the claim. It distinguishes confirmed by a note you read from confirmed by a note nobody read — the second is fidelity to your own summary, which is not the same as truth.

Expect several cannot verify verdicts and treat them as correct.

head -6 .claude/agents/citecheck.md

Look at the tools: line — Read, Glob, Grep, Bash. There is no Write. Now ask it to fix something and watch it decline, not because it was told to but because there is nothing to decline with. That is the bottom layer, and it is the only one that cannot be talked out of.

Last check before you upload

python3 tools/texcheck.py writing/myplan.tex

Three things, and they are specifically the three that break somebody else's build:

FAIL preamble in a fragment. These lines belong in main.tex: 1:\documentclass{article} 2:\usepackage{natbib} FAIL unbalanced environments: itemize 1 begin, 0 end FAIL cite key(s) not in refs.bib — these render as (?): nobody:ghost2099 note 1 open [GAP:] marker(s), 0 [WEB:] marker(s) Gaps are a result, not a defect. Leave them in.

It does not need LaTeX installed. It is a text check, because requiring a TeX install would have excluded half the room — and because what it is looking for is visible in the source anyway.

6 · Upload to the shared Overleaf project — 10 min

The link is on the slide. It opens the project with edit access.

  1. Rename your file. In Overleaf, select the groups folder, then Upload:
    groups/firstname-lastname.tex     # e.g. groups/alice-nguyen.tex

    Upload it as myplan.tex and you will silently overwrite whoever went before you. Say the filename out loud before anyone uploads.

  2. Paste your entries into refs.bib, at the end. Your keys are prefixed, so nothing can collide.
  3. Add one line to main.tex, in the marked block:
    \input{groups/firstname-lastname}

Overleaf is a real-time collaborative editor, so twenty people each adding one line to main.tex is exactly what it is built for. Watch the PDF rebuild with your section in it — that is the moment the session is for.

7 · The instructor assembles — 10 min

Live, on the projector. Compile, look at what twenty people produced in one document, and see what broke.

Something usually does, and that is the useful part. The three failures in order of likelihood are in the instructor notes below, with the fix for each.

8 · If time: a skill of your own — 15 min

A skill is a folder with a SKILL.md in it. Open .claude/skills/design/SKILL.md — that is the entire format: frontmatter with a name and a description, then instructions.

> Create a skill called <name> that <the thing you kept re-explaining to Claude today>.
use it when
subagentthe point is a narrower tool list — it must not be able to do something, or it needs its own context window
skillthe point is a consistent procedure — the same steps, the same order, every time
neitherit runs once. Just ask. Do not build a thing.

citecheck is an agent because the point is what it cannot do. design is a skill because the point is the order it works in.

For the instructor

The package ships an instructor/ folder with main.tex, a worked example-plan.tex, and the setup steps. Fifteen minutes, once, before the session.

  1. New Project → Blank Project. Upload main.tex, replacing the default.
  2. Create a groups folder and upload example-plan.tex into it. It gives the class something to look at and proves the \input wiring works before anyone depends on it.
  3. Create refs.bib at the top level and paste in the header comment from the package's refs/refs.bib, so the key-prefix rule is visible to anyone who opens it.
  4. Recompile. Title page, table of contents, one example section. If it does not work now it will not work with twenty people in it.
  5. Share → link sharing → anyone with the link can edit. Put the link on a slide, not in the downloadable package.

When it breaks

symptomcause and fix
Every citation is (?), the References section is gone, the log says Repeated entryTwo people used the same cite key. Download the project (Menu → Download → Source) and run python3 tools/bibcheck.py refs.bib — it names the duplicate. Prefix one and recompile.
File groups/xyz.tex not foundThe \input line was added but the upload failed, or the filename does not match. Check the file tree.
Something unhelpful about a missing \begin{document}A stray \documentclass or \usepackage inside a group file. texcheck.py catches this before upload, which is why it is in the attendee steps.
One citation is (?), everything else is fine, exit code 0That key has no entry. Localised and silent — the opposite of the duplicate failure.

Afterwards, turn link sharing off. The link grants edit access to anyone who kept it, permanently. Or treat the project as disposable and abandon it.

What it teaches

Making it yours