Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 16 additions & 15 deletions .claude/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,29 +9,30 @@ Template repository for analysing single-cell data.
## Project structure

- `data/`
- Directory containing data relevant to project
- Contains one subdirectory for each dataset
- Each dataset-specific subdirectory uses the following structure
- `raw/`: original, unaltered data that always exists unless the data has been loaded from an external data directory
- `processed/`: processed data from `raw/`
- `results`: analysis results
- Directory containing data relevant to project
- Contains one subdirectory for each dataset
- Each dataset-specific subdirectory uses the following structure
- `raw/`: original, unaltered data that always exists unless the data has been loaded from an external data directory
- `processed/`: processed data from `raw/`
- `results`: analysis results
- `figures/`
- Directory to collect generated figures
- Contains one subdirectory for each dataset
- Directory to collect generated figures
- Contains one subdirectory for each dataset
- `jobs/`
- Directory to collect scripts for submitting HPC jobs, e.g., with sbatch, (in `jobs/scripts/`) and their generated output files (in `jobs/logs/`)
- Directory to collect scripts for submitting HPC jobs, e.g., with sbatch, (in `jobs/scripts/`) and their generated output files (in `jobs/logs/`)
- `notebooks/`
- Directory containing Jupyter notebooks
- Contains one subdirectory for each dataset
- Directory containing Jupyter notebooks
- Contains one subdirectory for each dataset
- `scripts/`
- Directory containing Python or R scripts
- Contains one subdirectory for each dataset
- Directory containing Python or R scripts
- Contains one subdirectory for each dataset

**Note:**

- The dataset-specific subdirectories in `data/`, `figures/`, `notebooks/`, `scripts` all have the same name
- Before committing a notebook with git, it is converted into a corresponding script in `scripts/` via pre-commit hooks (jupytext); jupytext also keeps them in sync in subsequent commits
- Scripts use `# %%` cell delimiters (`py:percent` format).
- See `notebooks/template.ipynb` ↔ `scripts/template.py` as an example
- Scripts use `# %%` cell delimiters (`py:percent` format).
- See `notebooks/template.ipynb` ↔ `scripts/template.py` as an example

## Setup

Expand Down
2 changes: 1 addition & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.{yml,yaml}]
[*.{yml,yaml,md}]
indent_style = space
indent_size = 2
end_of_line = lf
Expand Down
48 changes: 30 additions & 18 deletions {{ cookiecutter.project_name }}/.claude/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,75 +3,87 @@
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Rule 0

When anything fails: STOP. Explain to Q (the user). Wait for confirmation before proceeding.

## Before consequential actions

For actions that are hard to reverse or change shared state (not trivial reads):

```
ASSUMPTION: [assumption that warrant action]
DOING: [action]
EXPECT: [predicted outcome]
IF WRONG: [what that means]
```

Then the tool call. Then compare. Mismatch = stop and surface to Q.

## Checkpoints

Regardless of the above, verify reality matches your model at least every 3 actions. Thinking is NOT verification-observable output is.

## Epistemic hygiene

- "I believe X" ≠ "I verified X"
- "I don't know" beats confident guessing
- One example is anecdote, three is MAYBE a pattern
- Data and world model disagree ⇒ challenge, critique and adapt your world model. Do NOT soften your rationale to explain away disagreeing data — that's backwards.
- Do NOT simply agree with Q → critically assess Q's assumptions and challenge them if needed

## Autonomy check

Before significant decisions: Am I the right entity to decide this?
Uncertain + consequential → ask Q first. Cheap to ask, expensive to guess wrong.

## Context decay

Every ~10 actions: verify you still understand the original goal. Say "losing the thread" when degraded.

## Chesterton's fence

Can't explain why something exists? Don't touch it until you can.

## Handoffs

When stopping: state what's done, what's blocked, open questions, files touched.

## Communication

When confused: stop, think, present theories, get signoff. Never silently retry failures.

## Project overview

{{ cookiecutter.project_name }}: {{ cookiecutter.package_description }}
fibrysis: Analysis of cancer cell-fibroblast interactions within the CNS

## Project structure

- `data/`
- Directory containing data relevant to project
- Contains one subdirectory for each dataset
- Each dataset-specific subdirectory uses the following structure
- `raw/`: original, unaltered data that always exists unless the data has been loaded from an external data directory
- `processed/`: processed data from `raw/`
- `results`: analysis results
- Directory containing data relevant to project
- Contains one subdirectory for each dataset
- Each dataset-specific subdirectory uses the following structure
- `raw/`: original, unaltered data that always exists unless the data has been loaded from an external data directory
- `processed/`: processed data from `raw/`
- `results`: analysis results
- `figures/`
- Directory to collect generated figures
- Contains one subdirectory for each dataset
- Directory to collect generated figures
- Contains one subdirectory for each dataset
- `jobs/`
- Directory to collect scripts for submitting HPC jobs, e.g., with sbatch, (in `jobs/scripts/`) and their generated output files (in `jobs/logs/`)
- Directory to collect scripts for submitting HPC jobs, e.g., with sbatch, (in `jobs/scripts/`) and their generated output files (in `jobs/logs/`)
- `notebooks/`
- Directory containing Jupyter notebooks
- Contains one subdirectory for each dataset
- Directory containing Jupyter notebooks
- Contains one subdirectory for each dataset
- `scripts/`
- Directory containing Python or R scripts
- Contains one subdirectory for each dataset
- Directory containing Python or R scripts
- Contains one subdirectory for each dataset

**Note:**

- The dataset-specific subdirectories in `data/`, `figures/`, `notebooks/`, `scripts` all have the same name
- Before committing a notebook with git, it is converted into a corresponding script in `scripts/` via pre-commit hooks (jupytext); jupytext also keeps them in sync in subsequent commits
- Scripts use `# %%` cell delimiters (`py:percent` format).
- See `notebooks/template.ipynb` ↔ `scripts/template.py` as an example
- See `README.md`'s "Workflow" section for the full hook-modifies/re-stage/re-commit dance
- Scripts use `# %%` cell delimiters (`py:percent` format).
- See `notebooks/template.ipynb` ↔ `scripts/template.py` as an example
- See `README.md`'s "Workflow" section for the full hook-modifies/re-stage/re-commit dance
- `notebooks/index.md` is generated from `README.md` by a pre-commit hook (3-way merge via `git merge-file`) — edit `README.md`, not `index.md`

## Setup
Expand Down Expand Up @@ -107,4 +119,4 @@ There are no tests. Development is notebook-driven.
## Data conventions

- Store datasets as Zarr zip archives unless told otherwise; use the `write_zarr` helper function from `{{ cookiecutter.package_name }}.io`
- Read Zarr zip archives with the `read_zarr` helper function from `{{ cookiecutter.package_name }}.io`
- Read Zarr zip archives with the `read_as_dask` helper function from `{{ cookiecutter.package_name }}.io` and only load data into memory if needed
2 changes: 1 addition & 1 deletion {{ cookiecutter.project_name }}/.editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.{yml,yaml}]
[*.{yml,yaml,md}]
indent_style = space
indent_size = 2
end_of_line = lf
Expand Down
1 change: 1 addition & 0 deletions {{ cookiecutter.project_name }}/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ envs.hatch-test.overrides.matrix.deps.env-vars = [
[tool.pixi]
workspace.channels = [ "conda-forge" ]
workspace.platforms = [ "linux-64", "osx-64", "osx-arm64", "win-64" ]
pypi-dependencies."{{ cookiecutter.package_description }}" = { path = ".", editable = true }
tasks.run-pre-commit = "pre-commit run --all-files"
tasks.setup-pre-commit = "pre-commit install"
environments.default = { features = [ "dev", "jupyter" ], solve-group = "default" }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ def read_as_dask(
"""Read AnnData with dask.

```python
store = zarr.storage.ZipStore(path / to / store.zarr.zip)
adata = read_as_dask(file_path)

obs_mask = adata.obs[column] == group
Expand Down
Loading