---
title: "Prepare a project for Claude Code and Codex: from setup to the first change"
source: "https://www.matteovincenti.com/en/blog/prepare-project-claude-code-codex"
language: en
author: "Matteo Vincenti"
published: 2026-10-25
category: "AI"
tags: ["Claude Code", "Codex", "AI agents", "Workflow"]
---

# Prepare a project for Claude Code and Codex: from setup to the first change

From an empty folder to a verified first change: AGENTS.md and CLAUDE.md instructions, tests, permissions and a handoff for coding agents.

![A laptop beside a folder of documents representing project structure, instructions and tests.](https://cdn.sanity.io/images/xrqkwry7/production/4e05c3fd3c96f4ae7455c1084cf19724a833213b-1536x1024.png?w=1400&fit=max&auto=format)

Category: AI · Tags: Claude Code, Codex, AI agents, Workflow

A new session with a coding agent can reopen the same questions: which folder should it use, how do the tests run, and which files may it change? When those answers live only in conversations, the project depends on what we remember to put back into the prompt.

Preparing a repository means making that information easy to find and connecting it to a result we can check. We will start with an empty directory, build a small CSV filename formatter, and give Claude Code or Codex a bounded change. You can also complete the whole exercise manually: establish passing tests, add a requirement that fails, then fix it without breaking the file extension.

A repository contains a project's files, usually tracked with Git; its *root* is the top-level directory. Projects in chat applications manage their own instructions and documents. This setup is for agents working on local files. Uploading the same documents to a chat does not open the repository.

If you already have a project, keep its setup. The section “Adapt the setup to your actual project” explains how to derive commands and constraints from existing files. The lab lets you try the complete sequence without touching your working code.

## Start with a project you can check

You need an editor, Node.js 22 or later, and npm. The directory commands below are for a macOS, Linux, or WSL terminal. If Node is missing, follow the [official installation instructions](https://nodejs.org/en/download). The function needs no additional packages, credentials, or services.

Create a new directory, separate from your working projects:

```bash
mkdir agent-project-example
cd agent-project-example
mkdir src test tasks
node --version
npm --version
```

Run every command from `agent-project-example` from this point onward. Open that directory in your editor. You will write the following seven files as you work through the steps; no Claude or Codex command generates them:

```txt
agent-project-example/
├── package.json
├── src/
│   └── export-name.mjs
├── test/
│   └── export-name.test.mjs
├── AGENTS.md
├── CLAUDE.md
├── tasks/
│   └── export-name.md
└── handoff.md
```

Start with the three files needed to run the example. `package.json` names the project and defines the test command:

```json
{
  "name": "csv-export-name-example",
  "private": true,
  "type": "module",
  "engines": { "node": ">=22" },
  "scripts": { "test": "node --test --test-reporter=spec test/export-name.test.mjs" }
}
```

Put the initial version of the function in `src/export-name.mjs`:

```javascript
import { extname } from 'node:path';

export function exportName(fileName) {
  const extension = extname(fileName);
  const base = fileName.slice(0, fileName.length - extension.length);
  const stem = base.trim().toLowerCase()
    .replace(/[^a-z0-9]+/g, '-')
    .replace(/^-|-$/g, '');

  return `${stem || 'export'}${extension}`;
}
```

`exportName` accepts a complete filename such as `Report Marzo.csv`. It separates the extension, lowercases the preceding text, and replaces spaces and other separators with hyphens. The result is `report-marzo.csv`. It does not read or write files.

Create `test/export-name.test.mjs` with these five cases:

```javascript
import assert from 'node:assert/strict';
import test from 'node:test';
import { exportName } from '../src/export-name.mjs';

test('keeps the CSV extension while formatting an ASCII name', () => {
  assert.equal(exportName('Report Marzo.csv'), 'report-marzo.csv');
});

test('collapses separators and retains digits', () => {
  assert.equal(exportName('  Report__Marzo---2026.csv'), 'report-marzo-2026.csv');
});

test('preserves the exact extension spelling', () => {
  assert.equal(exportName('Report Marzo.CSV'), 'report-marzo.CSV');
});

test('formats internal dots without changing the final extension', () => {
  assert.equal(exportName('Report finale.v2.csv'), 'report-finale-v2.csv');
});

test('uses the existing fallback when the base has no ASCII letters or digits', () => {
  assert.equal(exportName('  ---  .csv'), 'export.csv');
});
```

Node's [built-in test runner](https://nodejs.org/api/test.html) runs the checks; `assert.equal` compares the result with the expected value. Run:

```bash
npm test
```

The initial result should be five passing tests and no failures. There is no need to run `npm install`: the project has no dependencies to download. If the command fails to start or a test fails, resolve that first. An agent making a change needs to distinguish an existing defect from one its patch introduces.

The code and test sequence used for this guide was verified with Node.js 22.23.4 and npm 10.9.9 on macOS arm64. That checks the executable example; it does not measure Claude Code or Codex effectiveness or token usage.

## Keep project instructions in one place

Rules that survive from one assignment to the next belong in the project: the test command, where to run it, and the boundaries on changes. The requirements for an individual change will go in a separate document.

Create `AGENTS.md` in the root:

```markdown
# Repository instructions

This dependency-free Node.js example formats CSV export names.

- Work from the project root. Use Node.js 22 or later.
- Read the task file named in the prompt and handoff.md before editing.
  These are custom project documents, not automatically loaded files.
- Run npm test before and after a source change. No installation is needed.
- Keep the acceptance tests unchanged while implementing the task.
  If a test conflicts with the request, report the conflict first.
- Preserve the filename extension and existing regression-test behavior.
- Do not add packages, edit unrelated files, commit, push, or publish.
- Update handoff.md with changed files, the exact command, the observed
  result, and remaining work. Report a check as blocked if it cannot run.
```

I use English for reusable documents in this example; choose the language your team works in. Each line concerns an action that can be checked. A generic description of the ideal agent would add little here.

Next to it, create `CLAUDE.md` containing one line:

```txt
@AGENTS.md
```

Write that line as plain text in the file, without code fences. Claude Code imports the referenced file relative to `CLAUDE.md`. This avoids maintaining two copies of the rules; imported content still uses context. [Import documentation](https://code.claude.com/docs/en/memory#import-additional-files).

Codex discovers instructions at startup, combining global guidance with files from the project root down to the current directory. Within one directory, `AGENTS.override.md` takes precedence over `AGENTS.md`. Start this example from its root, and open a new session after changing instructions. [AGENTS.md discovery](https://learn.chatgpt.com/docs/agent-configuration/agents-md#how-codex-discovers-guidance).

Recent Claude Code versions can also read `AGENTS.md` directly, subject to other instruction files and settings. The small `CLAUDE.md` makes the import explicit. Claude's `/context` and `/memory` help inspect memory files; for Codex, use the loading checks in its [official guide](https://learn.chatgpt.com/docs/agent-configuration/agents-md#verify-your-setup).

These files tell the agent how to work. Writing “do not push” does not revoke Git credentials or technically block the command: access controls are configured in the client. This local exercise needs project files and test execution, with no production access. See the guides to [Claude Code permissions](https://code.claude.com/docs/en/permissions) and [Codex security](https://learn.chatgpt.com/docs/agent-approvals-security). The [harness engineering article](https://www.matteovincenti.com/en/blog/agent-harness-engineering-controls) develops the distinction between instructions and controls enforced by software.

## Give the first task a precise boundary

The initial function drops accented letters: `Caffè già pagato.csv` becomes `caff-gi-pagato.csv`. We want to keep their base letters, producing `caffe-gia-pagato.csv`. The extension must remain intact, including uppercase `.CSV`.

Write `tasks/export-name.md`:

```markdown
# Retain decomposable Latin letters in CSV export names

## Requested behavior

exportName receives a complete CSV filename, not a path.
Convert decomposable Latin accents to their ASCII letters in the base name:
- Caffè già pagato.csv -> caffe-gia-pagato.csv
- Cafe\u0301 résumé.csv -> cafe-resume.csv
  (\u0301 is the combining acute accent used in the JavaScript test.)

## Acceptance conditions

- Preserve the exact final extension, including .CSV.
- Preserve lowercasing, separator collapsing, digits, internal-dot handling,
  and the export fallback covered by the five existing tests.
- Pass all six tests with npm test.
- Keep test/export-name.test.mjs unchanged while implementing the source fix.

## Scope and delivery

Change src/export-name.mjs and record the result in handoff.md.
Use built-in APIs. Do not add dependencies or filesystem I/O.
General transliteration (including ø and ß), non-Latin scripts, paths,
hidden files, and malformed inputs are outside this task.
Report the changed files and the exact verification result.
```

This document defines what to change and what to preserve. Its filename is a convention for this example. Claude and Codex do not automatically load it because it lives in a folder named `tasks`; we will name it in the request.

Before changing the source, append this sixth test to `test/export-name.test.mjs`, keeping the original five:

```javascript
test('retains decomposable Latin letters in accented CSV names', () => {
  assert.equal(exportName('Caffè già pagato.csv'), 'caffe-gia-pagato.csv');
  assert.equal(exportName('Cafe\u0301 résumé.csv'), 'cafe-resume.csv');
});
```

The second input contains an `e` followed by the Unicode combining accent `\u0301`. It can look identical to `é` on screen while having a different representation in the string.

Run `npm test` again. The expected result is now five passing tests and one failure, with this difference:

```txt
actual:   caff-gi-pagato.csv
expected: caffe-gia-pagato.csv
```

Record that starting point. Create `handoff.md` with the following text if it matches the result you just observed. Otherwise, record the actual failure and resolve the discrepancy before continuing.

```markdown
# Export-name handoff

State: the source still has the original ASCII-only formatter.
The sixth test has been added for decomposable Latin accents.

Last check: npm test — five tests passed and one failed.
Actual: caff-gi-pagato.csv
Expected: caffe-gia-pagato.csv

Next: read tasks/export-name.md, change only the base-name formatting
in src/export-name.mjs, keep the six tests unchanged, then run npm test.
No source fix has been applied yet.
```

`handoff.md` is another document we have chosen to use. It records the current state and the next step; the client does not treat the filename as automatic memory.

## Hand the task to an agent, or finish it manually

If Claude Code or Codex is already installed and connected to your account, start **one of them** from the example's root:

```bash
claude
```

or:

```bash
codex
```

If you need to set up a client, first follow the [Claude Code quickstart](https://code.claude.com/docs/en/quickstart) or the [Codex CLI quickstart](https://learn.chatgpt.com/docs/codex/cli). Agent usage depends on your account and plan; you can finish the Node exercise without starting either client.

Before assigning the task, check that the client started with the expected instructions. In Claude Code, `/context` shows Memory files and `/memory` lists their paths: look for the `CLAUDE.md` you just created. In a fresh Codex session, you can ask:

```txt
Without reading additional files, summarize the repository instructions
already available in this session. Name their source paths and the test command.
Do not change files or run commands.
```

Compare the answer with the file: expect the example's root, `npm test`, and the constraint on acceptance tests. If something is missing, check the working directory and the official discovery guide before continuing. The summary is a diagnostic check; test output will verify the work. Asking `Read AGENTS.md` immediately would skip this distinction: the file could be read on request even if it was not loaded at startup.

After that check, send the task:

```txt
Read AGENTS.md, tasks/export-name.md, and handoff.md.
Explain the current state and run npm test before editing.
Implement only the source change requested by the task.
Keep the acceptance tests unchanged.
Run npm test again, inspect the changed files, and update handoff.md
with the observed result and any remaining work.
Do not commit, push, or publish.
```

The request points to the files describing the work instead of copying them into the conversation. Check that the agent has read the task and observed the sixth test failing. A proposal to reorganise the project or change the expected result would expand the work beyond this assignment.

For the manual path, or to compare the proposed patch, here is the complete corrected `src/export-name.mjs`:

```javascript
import { extname } from 'node:path';

export function exportName(fileName) {
  const extension = extname(fileName);
  const base = fileName.slice(0, fileName.length - extension.length);
  const stem = base.normalize('NFD').replace(/\p{M}/gu, '').trim().toLowerCase()
    .replace(/[^a-z0-9]+/g, '-')
    .replace(/^-|-$/g, '');

  return `${stem || 'export'}${extension}`;
}
```

The change adds `NFD` normalization and removes combining marks with `\p{M}` from the base name only. NFD decomposes characters such as `è` into a letter and its accent. The existing code continues to handle lowercasing, separators, and the fallback. [Unicode normalization in JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/normalize).

Applying the change to the right part of the name matters more than the patch's size. Formatting the whole `fileName` produces `report-marzo-csv`, for example: the accent handling would be fixed, but the extension would lose its dot. The first test already catches that regression.

## Check the result and leave a useful handoff

With the corrected source and the six tests unchanged, run:

```bash
npm test
```

You should get six passing tests and zero failures. Read the source as well: the extension extraction and return expression should still match the initial version. That comparison shows whether the patch changed the intended part, even when the suite is green.

If you used an agent, compare the changed files with the task's scope. The new test was fixed before implementation began, so the expected edits are to the source and the handoff. In this example you can compare them with the article's blocks; in a versioned repository, use your editor's or Git's diff view. Git is not required to run this exercise.

When the result matches, update `handoff.md`:

```markdown
# Export-name handoff

State: the requested source fix is implemented.
Changed: src/export-name.mjs and this handoff.
The source applies NFD normalization and combining-mark removal to
the base name. Extension handling is unchanged.

Last check: npm test — six tests passed, zero failed.
The acceptance tests were unchanged during the source fix.
Remaining work: review the source diff. No commit or publication requested.
```

The note records a specific outcome and leaves review as the next action. If the tests did not run, record why. “It should work” is not a result to pass to the next session.

To resume in a fresh session from the same root, use:

```txt
Read AGENTS.md, tasks/export-name.md, and handoff.md.
Compare the handoff with the current source and tests.
Run npm test and report any difference from the recorded state.
Do not change files yet.
```

The new session now has a bounded question: does the project still match the note? If someone has changed the tests or source in the meantime, that difference should surface before further work. The guide to [context engineering, memory, and handoffs](https://www.matteovincenti.com/en/blog/context-engineering-memory-handoffs-wiki) explains how to choose what information to retain.

## Adapt the setup to your actual project

My repositories have different arrangements: applications with their own commands, a repository coordinating other projects, and instructions generated from a shared source. Writing “run tests from the root” without identifying which project owns the change leaves the agent to resolve a decision we should already have made.

Start with an inspection limited to the assignment. Read the existing instructions, README, dependency manifest, lockfile, and relevant CI checks. Follow the scripts they invoke too: a name such as `build` or `test` says little about what will run. In a Git repository, `git status --short` and `git diff --stat` help identify existing changes that need to be preserved.

You can ask the agent to do that reading:

```txt
Inspect the existing instructions and the files relevant to this task.
Do not edit files, install dependencies, or run project commands yet.
Identify the project that owns the change and its working directory.
Read the README, manifests, lockfiles, relevant CI checks, and the scripts
they invoke. Report the runtime, package manager, prerequisites,
generated files and their editable sources.
For each proposed check, cite its source and explain what it verifies.
Separate observed configuration, planned work, and checks not yet run.
Report conflicts between instructions and code.
```

My [log-service-js repository](https://github.com/MatteoVincenti/log-service-js/blob/e2dfd28029e510037309018841d74a4e39e7d8e4/package.json) provides a concrete example: its manifest exposes `build`, `watch`, `serve`, and `start`, but no `test` script; the [README](https://github.com/MatteoVincenti/log-service-js/blob/e2dfd28029e510037309018841d74a4e39e7d8e4/README.md) still lists tests as a TODO. Copying `npm test` from this lab would immediately introduce an incorrect instruction.

A small map makes the difference visible. This one compares the public project's files at the linked revision with the guide's lab:

_Adapt the setup to your actual project_

| Item | CSV lab | Logging project |
| --- | --- | --- |
| Command and directory | `npm test`, example root | `yarn build`, project root according to the README |
| Command source | `package.json → scripts.test` | `package.json → scripts.build`, invoking `scripts/build.js` |
| Prerequisites | Node 22+, npm; no additional packages | Node, Yarn, and the project's dependencies available |
| Available check | Six behavioural cases after the fix | Build through esbuild; no test script declared |
| Verification state | Six tests passed in the run described above | Configuration read; build not run |

That changes the decision. In the lab, we can assign the fix straight away. If the real project lacks a check for the behaviour being changed, the first assignment is to establish one representative check. A successful build is useful, but it does not tell us whether a log message reaches the right destination. Where a relevant check already exists, run it before the patch and retain the result as a baseline. If it needs an unavailable service or credential, record that blocker before estimating the work.

There is no need to map the entire system before every small edit. The initial inspection becomes a reference to update when commands or the area of work change. [Claude Code's best practices](https://code.claude.com/docs/en/best-practices) likewise reserve more elaborate planning for problems that need it.

The [openai-python instructions](https://github.com/openai/openai-python/blob/main/AGENTS.md), for example, explain generated code and the relevant commands. [VS Code's instruction file](https://github.com/microsoft/vscode/blob/main/.github/copilot-instructions.md) refers to the project's checks and existing development processes. They help illustrate what to document; copying their commands into another repository would create incorrect guidance.

Sharing instructions requires a similar choice. The `AGENTS.md` import is enough for this lab. If a project generates configurations for several clients, identify the editable source, the derived files, and the actual regeneration command; use the generator's existing comparison check. Editing only a generated copy means losing the correction on the next regeneration. I would introduce that mechanism when divergent copies create a concrete maintenance problem, not to prepare seven files.

Keep instructions that apply to most tasks in the stable guidance, and point to specialist procedures when a task needs them. The official videos [Getting started with Codex](https://www.youtube.com/watch?v=px7XlbYgk7I) and [Claude Code best practices](https://www.youtube.com/watch?v=gv0WHhKelSE) also describe this approach: commands and a project map in the instructions, details and progress in dedicated documents. Finding the relevant instruction matters more than a line count.

For a versioned project's handoff, add the starting revision, outstanding local changes, the command with its working directory, and the result. If the task created temporary builds, logs, or containers, record what you removed and what is still needed; avoid broad cleanup of shared dependencies or data. This information changes with the work and belongs in the handoff.

A skill would add a procedure to maintain for a CSV change that is already well defined. Introduce one when an activity repeats and needs its own steps, such as a review with shared criteria. The guide to [skills for Claude and Codex](https://www.matteovincenti.com/en/blog/optimise-skills-claude-codex) covers that case. An MCP server becomes useful when the task needs data or actions in an external system; file access and a terminal are sufficient here.

The lab's final check is straightforward: a fresh session finds `npm test`, gets six passing tests, and recognises that the diff still needs review. Look for the same handoff in a real project: a bounded assignment, a traceable command, and a state the next person or session can check.
