---
name: irb-form-generator
description: Institution-agnostic IRB / ethics-committee paperwork pipeline — turns one config.toml (+ cv.toml / 中文計畫摘要.md) into an institution's official DOCX forms (filled or rebuilt), PDFs, a ■/□ checklist and a Win/Mac layout gate, for every submission phase (new case, amendment, continuing review, closure, SAE, etc.). Ships the KFSYSCC form pack; onboards any other institution from its blank Word forms. Use when user mentions IRB, REC, ethics review, human subjects research, filling official DOCX forms, KFSYSCC, or wants to adapt the pipeline to their own hospital's forms.
---

# IRB-in-Hurry Skill

Institution-agnostic IRB form pipeline: plain-text study sources (`config.toml` +
referenced `cv.toml` / `中文計畫摘要.md`) + an **institution profile**
(`institutions/<id>/`) → official DOCX forms → PDF/PNG → layout gate. KFSYSCC
(`irb_in_hurry/institutions/kfsyscc/`, 43 forms) is the reference pack.

## Running it

Everything runs through the `irbh` command, in the **study folder** (the one
holding `config.toml`). If `irbh` is not on PATH, use `uvx --from irb-in-hurry irbh …`
(or `uv tool install irb-in-hurry` once; from GitHub:
`uv tool install git+https://github.com/htlin222/irb-in-hurry`); inside a checkout of the
irb-in-hurry repo, `uv run irbh …` (or the matching `make` target) does the same.
`irbh doctor` reports what is missing (LibreOffice, poppler, form font, blanks).

## Step 0: Which institution?

Before anything else, settle which committee the user is submitting to:

| Situation | Action |
|---|---|
| `institution` in `config.toml` matches the user's committee | proceed |
| Committee has a pack (`irbh institutions` lists them) | set `institution = "<id>"` in `config.toml` |
| New committee, user has blank forms or a forms URL | follow [onboard-institution.md](references/onboard-institution.md), then return here |
| Unknown | ask: "Which hospital or committee are you submitting to?" |

Everything institution-specific (committee name, IRB-number label, submission
email, paper size, margins, font, form list, routing) comes from
the pack's `profile.toml` + `forms.py`. **Never hardcode these in code
or generators**: read `institution()` (from `irb_in_hurry.docx_utils`).
Method and invariants: `docs/METHODOLOGY.md`.

## Quick Start

Users do NOT need to edit config files by hand. Just provide any free-form text:

```
User: "我想做一個回溯性研究，看2018-2023年肺癌免疫治療的甲狀腺功能，大約200人。我是腫瘤內科陳雅文。"
```

Claude will:
1. Save raw text to `raw/`
2. Distill into `config.toml` + `cv.toml` + `中文計畫摘要.md` (see [distill.md](references/distill.md)); run `irbh check`
3. Ask for any missing required fields (IRB number, dates)
4. Run `irbh all` + `irbh review`
5. Show dashboard and review opinions

### Manual alternative

```bash
# If user prefers to edit the sources directly:
irbh init tdxd-her2low   # optional starting point
vim config.toml cv.toml 中文計畫摘要.md
irbh check && irbh all
irbh review
```

## Workflow Overview

When a user provides a study topic, proposal, or any text:

1. **Save raw input** -- Write to `raw/proposal_YYYYMMDD.md`
2. **Distill to config** -- Study type, dates, subjects → `config.toml`; PI/co-PI → `cv.toml`; background/objectives/methods prose → `中文計畫摘要.md` (see [distill.md](references/distill.md)). `irbh check` must pass
3. **Confirm with user** -- Ask about any missing required fields (IRB number, exact dates)
4. **Generate forms** -- `irbh all` → DOCX + PDF + PNG previews + dashboard
5. **Run reviewer** -- `irbh review` → `reviewers/review_*.md`
6. **Layout safety gate** -- `irbh validate` (part of `irbh all`; run `irbh templates` once first).
   Must be 0 errors. Read `output/layout_report.md`, then view `output/preview/compare/*.png`
   (official blank left, generated right) and report any visible drift to the user.
   Remind the user to submit the PDF (fonts embedded → identical on Windows/Mac).
7. **Fix findings** -- Address required revisions from reviewer
8. **Update checklist** -- Track manual steps via `checklist.md`

## Study Type Classification (generic)

| Study Type | Review Type | Key Config Flags |
|---|---|---|
| Retrospective chart review | expedited | `type: retrospective`, `consent_waiver: true` |
| Prospective observational | expedited or full_board | `type: prospective` |
| Clinical trial (drug) | full_board | `type: clinical_trial`, `drug_device: true` |
| Clinical trial (device) | full_board | `type: clinical_trial`, `drug_device: true` |
| Genetic research | full_board | `type: genetic`, `genetic: true` |
| Multi-center study | varies | `multicenter: true` |

See [study-types.md](references/study-types.md) for the full decision tree.

## Phase to Forms Mapping (KFSYSCC pack)

Phase names are generic; the forms per phase come from the active
institution's `PHASE_FORMS`. For KFSYSCC:

| Phase | Forms | When |
|---|---|---|
| new | SF001, SF002, SF094 + conditional | Initial submission |
| amendment | SF014, SF015, SF016, SF094 | Protocol changes |
| re_review | SF019 | Responding to IRB queries |
| continuing | SF030, SF031, SF023 | Annual review |
| closure | SF036, SF037, SF038, SF023 | Study completion |
| sae | SF079, SF044/SF074, SF080, SF024 | Adverse events |
| ib_update | SF082, SF083 | Investigator's Brochure updates |
| import | SF066, SF067, SF068, SF093 | Drug import |
| suspension | SF047, SF048 | Study pause |
| appeal | SF077, SF054 | Decision appeal |

The form selector (`irb_in_hurry/form_selector.py`) reads the active institution's `forms_module` and adds conditional forms based on study type, review type, and config flags.

## Config Schema (Key Fields)

```toml
# config.toml — "@file" / "@file#key" values are replaced by that file's content
institution = "kfsyscc"        # institution pack id (`irbh institutions`)
phase    = "new"               # new | amendment | continuing | closure | sae | ...
pi       = "@cv.toml#pi"       # [pi] name, name_en, dept, phone, email
co_pi    = "@cv.toml#co_pi"    # [[co_pi]] entries (optional)
proposal = "@中文計畫摘要.md"   # ## 研究背景 / 研究目的 / 納入條件 / 統計分析 ...

[study]
irb_no      = ""               # IRB case number (blank until assigned)
title_zh    = ""
title_en    = ""
type        = "retrospective"  # retrospective | prospective | clinical_trial | genetic
review_type = "expedited"      # exempt | expedited | full_board
drug_device = false
genetic     = false
multicenter = false

[dates]
study_start = ""
study_end   = ""

[subjects]
planned_n      = 0
consent_waiver = false
```

Phase switches never re-dump the file: `irbh closure` == `irbh all --phase closure` (one-off);
`irbh set-phase closure` persists it by editing only the `phase =` line.

See [config-schema.md](references/config-schema.md) for the complete field reference.

## Checkbox Convention

- `check(True)` returns **U+25A0** (filled square) = checked/yes
- `check(False)` returns **U+25A1** (empty square) = unchecked/no

All forms use this convention via `docx_utils.check()`.

## Project Structure

Study folder (where `irbh` runs):

```
config.toml                    # Study metadata (single source of truth) + `institution`
cv.toml                        # Study team (@cv.toml#pi, @cv.toml#co_pi)
中文計畫摘要.md                 # Proposal prose (@中文計畫摘要.md)
institutions/<id>/             # (optional) a local pack, written by `irbh onboard <id>`
  profile.toml                 # names, labels, submission, page, font, blanks
  forms.py                     # FORM_REGISTRY + PHASE_FORMS (form pack)
  form_inventory.md            # (onboarded packs) what each blank contains
templates/<id>/                # official blank forms (gitignored ground truth; $IRB_TEMPLATES to share)
output/                        # Generated DOCX and PDF files
output/preview/                # PNG previews for visual validation
checklist.md                   # Auto-generated submission checklist
```

Packs are found local `institutions/<id>/` → installed (`irb_in_hurry.institutions`
entry point) → bundled. The package itself:

```
irb_in_hurry/
  cli.py                      # `irbh` command
  dashboard.py                # Terminal status dashboard (`irbh dashboard`)
  examples/                   # Complete example studies (`irbh init <name>`)
  institutions/kfsyscc/       # Bundled reference pack
  institution.py              # active profile loader
  config.py                   # config.toml loader: @references, Markdown, validation (ConfigError lists every problem)
  template_fill.py            # generic fill-the-blank generator
  onboard.py                  # blanks → draft profile/forms/inventory
  docx_utils.py               # Shared DOCX helpers (init_doc, add_p, add_ct, etc.)
  form_selector.py            # Phase + study type -> required forms
  generate_all.py             # Main orchestrator (--phase, --output, --verbose)
  set_phase.py                # Persist phase in config.toml, keeping comments
  checklist.py                # Generates checklist.md with status
  convert.py                  # DOCX -> PDF -> PNG pipeline
  generators/                 # KFSYSCC rebuild generators (reference pack)
    new_case.py               # SF001, SF002, SF094, SF011, SF022
    closure.py                # SF036, SF037, SF038, SF023
    consent.py                # SF003, SF004, SF005, SF062, SF063, SF075, SF090-092
    amendment.py              # SF014, SF015, SF016
    continuing_review.py      # SF030, SF031, SF032
    sae.py                    # SF079, SF044, SF074, SF080, SF024
    ib_update.py              # SF082, SF083, SF084, SF085
    import_forms.py           # SF066, SF067, SF068, SF093
    suspension.py             # SF047, SF048
    appeal.py                 # SF077, SF054
    re_review.py              # SF019
    other.py                  # SF076
```

## Form Details by Category (KFSYSCC pack)

- [New Case (新案審查)](references/new-case.md) -- SF001, SF002, SF094, SF003-005
- [Closure (結案審查)](references/closure.md) -- SF036, SF037, SF038, SF023
- [Amendment (修正案審查)](references/amendment.md) -- SF014, SF015, SF016
- [Continuing Review (期中審查)](references/continuing-review.md) -- SF030, SF031, SF032
- [SAE & Non-compliance (嚴重不良反應)](references/sae.md) -- SF079, SF044, SF074, SF080, SF024
- [Other Categories](references/other-categories.md) -- IB update, import, suspension, appeal
- [Study Types & Routing](references/study-types.md) -- Classification logic
- [Config Schema](references/config-schema.md) -- All config.toml fields and `@` references
- [Onboard an Institution](references/onboard-institution.md) -- New committee from its blank DOCX forms
- [Brainstorm](references/brainstorm.md) -- Research topic ideas (KFSYSCC + Taiwan epidemiology example)
- [Distill: Raw Text → Config](references/distill.md) -- How to extract config from free-form text
- [Reviewer Criteria](references/reviewer.md) -- Simulated IRB review checklist
- [Reviewer Guide](references/reviewer-guide.md) -- Rules of thumb, red flags, 45 CFR 46.111 training

## Validation

After generating forms:

1. Run `irbh pdf` to create PDFs and PNG previews (part of `irbh all`)
2. Read each `output/preview/*.png` to visually verify layout and content
3. Check `checklist.md` for remaining manual steps (signatures, content sections)
4. Run `irbh dashboard` for terminal status overview

## Adding New Generators

Prefer **filling the official blank** (layout-exact, a few lines per form):

```python
# institutions/<id>/forms.py
from irb_in_hurry.template_fill import blank_generator

generate_f01 = blank_generator("F01", fields={
    "計畫名稱": "{study.title_zh}",          # label in the blank → config format string
    "預計收案人數": lambda c: f"{c['subjects']['planned_n']} 人",
}, checks={
    "簡易審查": lambda c: c["study"]["review_type"] == "expedited",
})

FORM_REGISTRY = {"F01": ("新案申請書", "institutions.<id>.forms", "generate_f01")}
```

Rebuild with python-docx only when a blank can't be filled (text boxes,
content controls, PDF-only, generated prose):

```python
def generate_sfXXX(config: dict, output_dir: str) -> str:
    doc = init_doc()                                  # profile page setup + font
    add_p(doc, institution().heading, bold=True)      # never a literal hospital name
    add_header(doc, config)                           # uses institution().irb_no_label
    path = os.path.join(output_dir, f"SFXXX_{config['study']['irb_no']}.docx")
    doc.save(path)
    return path
```

Register it in the institution's `FORM_REGISTRY`. A `generators.*` module path
means the shared `irb_in_hurry.generators`; anything else is an absolute module
(`institutions.<id>.forms` for a local pack). Then add it to `PHASE_FORMS`.

## Submission

Read it from the profile (`submission:` block). `checklist.md` lists it.
For KFSYSCC: email irb@kfsyscc.org; 1 original + 1 copy to the IRB office (B1
administrative building); PI wet signature on signed forms.
