Project Types
Project Types
Standard, privacy-sensitive, course, and presentation projects, with their folders, .gitignore rules, and uses
Overview
Framework creates four kinds of project, plus a bare project with no structure. Each type sets the folders, the .gitignore, the render folders for Quarto, and the skills installed for AI assistants.
| Type | type value |
Use it for |
|---|---|---|
| Standard project | project |
Data analysis, research projects, pipelines, and reports |
| Privacy-sensitive project | project_sensitive |
Research with restricted data that must stay separate from shareable results |
| Course | course |
Teaching materials: slides, assignments, readings, and course documents |
| Presentation | presentation |
A single talk or slide deck |
| Bare | bare |
A settings file and pyproject.toml only, for building your own structure |
Pass the type to new() or to the command line.
import framework as fw
fw.new("Sales Analysis", "~/projects/sales-analysis", type="project")
fw.new("Patient Outcomes", "~/projects/patient-outcomes", type="project_sensitive")
fw.new("Data Science 101", "~/teaching/ds101", type="course")
fw.new("Q4 Report", "~/talks/q4-report", type="presentation")
python -m framework create --name "Sales Analysis" --path ~/projects/sales-analysis --type project
Without a type, an interactive session asks for one, and a script creates a bare project.
What Every Type Shares
Every type except bare includes these files.
settings.yml, withlanguage: python.pyproject.toml, which depends onframework-py.scaffold.py, which scaffold() runs..envwith empty credential placeholders, ignored by git.framework.db, ignored by git.- A root
_quarto.ymlfor rendering. AGENTS.md, the Framework skills, andCLAUDE.mdwhen Claude Code is selected.- A
.code-workspacefile for VS Code and Positron.
All four .gitignore templates ignore folders named private anywhere in the project, .env files, cache/, scratch/, and logs/ folders, framework.db, Quarto's working files, and Python environments. The Git guide lists the rules.
Folder names come from the package defaults and can be changed per type in your global settings, or per project in settings.yml.
Standard Project
The standard project is the default for data analysis. It separates inputs by stage, keeps outputs by kind, and has folders for notebooks, scripts, and reusable functions.
sales-analysis/
├── docs/ # project documentation (renders to outputs/docs/)
├── functions/ # reusable modules, on the import path after scaffold()
├── inputs/
│ ├── raw/ # data as received
│ ├── intermediate/ # cleaned and joined data
│ └── final/ # analysis-ready datasets
├── logs/
├── notebooks/ # Quarto and Jupyter notebooks
├── outputs/
│ └── notebooks/ # rendered notebooks
├── scratch/
├── scripts/
├── settings/ # split settings files
├── framework.db
├── pyproject.toml
├── scaffold.py
└── settings.yml
These folders are created the first time something is saved in them.
outputs/tables/,outputs/figures/,outputs/models/, andoutputs/reports/, by thesave_*()functions.outputs/cache/, by the cache.
The standard .gitignore does not ignore inputs/ or outputs/. Decide which data and results may be committed, and add rules for the rest. When a project holds data that must never be committed, use the privacy-sensitive type.
Use a standard project for most analysis work: research projects, data pipelines, exploratory analysis, and recurring reports.
Privacy-Sensitive Project
The privacy-sensitive project is for research with restricted data, such as protected health information. It splits every input stage and every kind of output into private and public folders.
patient-outcomes/
├── docs/
├── functions/
├── inputs/
│ ├── private/ # restricted data, never committed
│ │ ├── raw/
│ │ ├── intermediate/
│ │ └── final/
│ └── public/ # de-identified or aggregated data
│ ├── raw/
│ ├── intermediate/
│ └── final/
├── logs/
├── notebooks/
├── outputs/
│ └── private/
│ └── notebooks/ # rendered notebooks, which can show restricted data
├── scratch/
├── scripts/
├── settings/
├── framework.db
├── pyproject.toml
├── scaffold.py
└── settings.yml
The output folders follow the same pattern. outputs/private/tables/ and outputs/public/tables/, with matching pairs for figures, models, reports, and notebooks, are created when something is first saved there. The cache lives in outputs/private/cache/.
Protections
Several parts of Framework treat the private folders as restricted.
- Git. The
.gitignoreignores/inputs/private/,/outputs/private/, and every folder namedprivateorsensitive. It keepsREADME.mdand.gitkeepfiles, so the folder structure can be documented. - Outputs. The
save_*()functions save to private folders unless you passpublic=True. - Publishing. Every publishing function warns about files with
privatein their path and asks before it uploads them. - AI assistants.
AGENTS.mdtells assistants not to read the private folders. When Claude Code is selected,.claude/settings.jsondenies it access to them and to.env. Theframework-sensitive-dataskill is installed. - Settings.
security: sensitive: truemarks the project. - Audit. git_security_audit() passes on a new privacy-sensitive project. Turning on the
data_securityhook check runs it before every commit.
fw.git_hooks_enable("data_security")
Working with Private and Public Data
Restricted data goes into the private folders, and only aggregated or de-identified results move to the public ones. Register private files under four-part names with data_add(). The entries are locked by default, so a changed source file is caught.
import framework as fw
fw.scaffold()
fw.data_add("inputs/private/raw/patients.csv", name="inputs.private.raw.patients")
patients = fw.data_read("inputs.private.raw.patients")
by_region = patients.groupby(["age_group", "region"]).size().reset_index(name="n")
by_region = by_region[by_region["n"] >= 11]
fw.save_table(by_region, "patients_by_region", public=True)
Check git status before each commit, and review any file before it moves from a private folder to a public one.
Course
The course type organizes teaching materials. It has folders for slides, assignments, readings, course documents, modules, and shared data.
data-science-101/
├── assignments/ # renders to rendered/assignments/
├── cache/
├── course_docs/ # syllabus and schedules, render to rendered/course_docs/
├── data/ # datasets shared across the course
├── modules/ # notebooks, render to rendered/modules/
├── readings/
├── slides/ # reveal.js lectures, render to rendered/slides/
├── framework.db
├── pyproject.toml
├── scaffold.py
└── settings.yml
In a course, directories.notebooks points at modules/, so make_notebook() creates files there by default. Slides render as reveal.js presentations and the other folders as HTML. Course settings are kept inline in settings.yml, without split files.
Create materials with the dir and subdir arguments. An explicit dir is relative to the current folder, so run these calls from the project root.
fw.make_presentation("Introduction to Python", dir="slides", subdir="week-01")
fw.make_notebook("assignment-01", dir="assignments")
fw.make_notebook("syllabus", dir="course_docs")
The course .gitignore adds a rule for /slides/_rendered/. Rendered output in rendered/ is not ignored, so you can commit it to share it with students, or add a rule to keep it out of git. Student data belongs in a folder named private, which every template ignores.
Presentation
The presentation type is the smallest structure, for a single talk or slide deck.
q4-report/
├── cache/
├── data/
├── presentation.qmd # the slides, in reveal.js format
├── framework.db
├── pyproject.toml
├── scaffold.py
└── settings.yml
presentation.qmd starts with the reveal.js stub, titled with the project name. The root _quarto.yml renders it as reveal.js, and the output is written next to the source.
uv run quarto render presentation.qmd
Change the format in the front matter to produce another kind of document, such as html, pdf, or docx. Presentation settings are kept inline in settings.yml.
Use a presentation project for conference talks, committee presentations, and one-time briefings. For ongoing work with several deliverables, use a standard project.
Bare Project
A bare project has only settings.yml, pyproject.toml, .gitignore, and .framework/spec.json. It has no folders, no .env, no AI files, and no framework.db until scaffold() creates one. Use it as a starting point when none of the other types fits, and add folders with project_add_directory().
fw.project_add_directory(".", "interviews", "Interview transcripts", "inputs/interviews")
Choosing a Type
- Choose a standard project for analysis work whose data may be committed or kept out of git with ordinary rules.
- Choose a privacy-sensitive project when any data must never leave the machine or the secure environment, or when a reviewer needs to see a clear boundary between restricted and shareable material.
- Choose a course for a set of lectures, assignments, and readings.
- Choose a presentation for one deck.
A standard project can also be marked sensitive with security: sensitive: true in a framework.pub blueprint, which gives it the privacy-sensitive .gitignore and the framework-sensitive-data skill. The type of an existing project is recorded in project_type and is not converted automatically, so choose the type when you create the project.