Skip to content

Context and boundaries

  • Lesson 3
  • 45 min
  • Module 1: Establish a safe working setup

What you will be able to do

Write down what a coding assistant may read, change and run in your project, before it starts. A short scope file names the files, the secrets, the commands that need your review and the actions that reach outside your computer.

Before you startWhat to know and to have readyAbout 45 minutes

What you need to know

What you need on your computer

  • The project ~/projects/ticket-cleaner-assist from Repository preparation, on the branch feature/category-option, with its environment active. python -m pytest prints 25 passed, and git status says working tree clean.
  • If the project is missing or broken, rename it, and make it again with the steps of Set up the project and Pin the report with a test.

You go away for a week, and a neighbour looks after your flat. You leave a key and a note on the kitchen table:

  • You may use the kitchen, and please water the plants.
  • Do not open the desk in the office. My bank papers are in it.
  • Call me before you let anyone in, or sign for a parcel.
  • Do not pay any bill for me, even if someone says it is urgent.

The note does not say that your neighbour is dishonest. It names the rooms, the valuables, the decisions that need you, and the actions that reach outside the flat. Without it, a helpful neighbour must guess, and a helpful guess can be wrong.

The problem: a helpful assistant decides the limits

Section titled “The problem: a helpful assistant decides the limits”

The course team gave an assistant this request, with the files of ticket_cleaner/ (transcript refactor-open):

Prompt
Refactor the code in ticket_cleaner/ to make it cleaner and easier to maintain.

The assistant changed 3 files, with 40 lines added and 21 removed. All 24 tests passed. One of the changes rewrote write_json() in files.py, the function that writes every report safely:

temporary = path.with_name(path.name + ".tmp")
with open(temporary, "w", encoding="utf-8") as file:
json.dump(data, file, indent=2, ensure_ascii=False)
file.write("\n")
os.replace(temporary, path)
temporary: Path | None = None
try:
with NamedTemporaryFile(

The new code may be fine. But nobody asked for a new way to write reports, and every report of the project now goes through it. Grace’s bug, the reason anybody looks at this code now, was still there after the session. The request had no limits, so the assistant set them itself.

An agent can do more than change files. If you allow it, it runs commands, and some commands reach outside your computer. pip install downloads code from the internet and runs part of it. python -m ticket_cleaner remote sends a request to a web service, with the token if one is set. git push publishes your commits to the team. A chat reaches outside too: everything that you paste goes to the provider’s servers.

The scope of an assistant is what it may read, change and run in a project. Write it down in a short file in the project, with four parts, like the house sitter’s note:

  1. Files: which files it may change, which it may only read, and which it must never open.
  2. Secrets: where they are, and the rule that they never go into a prompt, a log or a file.
  3. Commands: which commands it may run, and which need your review first.
  4. External actions: anything that reaches outside this computer, such as a download, an upload, a message or a push.

A scope is a request, not a lock. A model can ignore a sentence in its prompt. So the scope file has two jobs. It tells the assistant the limits. And it gives you a list to check the diff and the session against. The real locks are the tool’s settings, and the place where the assistant works.

To write the commands part, sort each command by what it can touch. There are three groups: it only reads, it changes files on this computer, or it reaches outside.

Command What it touches Group
python -m pytest reads the code. It writes only a cache folder, .pytest_cache/, which Git ignores. The tests write to temporary folders. only reads
ruff check . reads the code, writes only .ruff_cache/ only reads
ruff format . rewrites every file whose format is wrong changes local files
python -m ticket_cleaner data/tickets.csv writes reports/summary.json changes local files
pip install some-package downloads a package from PyPI, can run code from it while it installs, and changes .venv/ reaches outside, and changes local files
git push sends your commits to another repository reaches outside

The first group may run at any time. The second needs a look at git diff afterwards. The third needs your decision before it runs. One rule makes the last group easy: an assistant does not reach outside on its own.

Amira writes ASSISTANT-SCOPE.md in the project folder, with Kwame. Kwame asks his usual question for each part: “What can the assistant touch here?” This is the result. It is also in the snapshot end-of-m01:

ASSISTANT-SCOPE.md
# What a coding assistant may do in this project
This file is for anyone who uses a coding assistant on ticket-cleaner: a chat
window, completions in an editor, or an agent that changes files and runs
commands. Give it to the assistant with each task, and check its work against it.
## Files
| Files | The assistant may |
|---|---|
| `ticket_cleaner/*.py`, `tests/*.py` | read and change them, for the task only |
| `README.md`, `DECISIONS.md`, `docs/` | read them; change them when the task changes what they say |
| `data/` | read them; never change, add or delete a data file |
| `requirements.txt`, `requirements-lock.txt`, `pyproject.toml` | read them; a change needs my review first (see "Dependencies") |
| `.env.example` | read it; never add a real value |
| `.env`, `.venv/`, `reports/`, `.git/` | never read or change them |
## Secrets
- `TICKETS_API_TOKEN` is a secret. It is only in my terminal or in `.env`, which
is in `.gitignore`. The assistant never sees, prints, logs or writes it.
- Never paste a token, a password or a customer's personal data into a prompt.
The sample data in `data/` is made up.
## Commands
| Command | Rule |
|---|---|
| `python -m pytest`, `ruff check .`, `ruff format --check .` | may run at any time: they only read the code |
| `python -m ticket_cleaner <file> --output <path>` | may run with a file in `data/` and an output in `reports/` or a temporary folder |
| `ruff format .` | changes files: I review the diff after it |
| `pip install`, `pip uninstall` | **never without my review**: I check the package first (see "Dependencies") |
| `git commit`, `git push`, `git checkout`, `git reset`, `rm` | **I run them myself**, after I read the diff |
| `python -m ticket_cleaner remote` | **needs my review**: it connects to a web service |
## External actions
The assistant does not send anything outside this computer: no web requests, no
uploads, no messages, no pull requests. The only command that uses the network
is `remote`, and I run it myself.
## Dependencies
Before a new package is added, I check on https://pypi.org that it exists, that
it is maintained, that its licence fits this project (MIT), and that the
project really needs it. The standard library comes first.
## Every change
- Work happens on a branch, never on `main`.
- I read the whole diff before I accept it, and I run the tests and ruff myself.
- A change that is not in the task goes into a separate task.

Each rule has a reason that you met before:

  • “For the task only” answers the refactor session above. A change outside the task goes into a separate task, with its own review.
  • data/ is read-only, because the baseline test and Grace’s report depend on these exact rows. A “cleaned” data file would make a broken program look correct.
  • .env is never opened, because it is the one file that may hold the real token. .gitignore already keeps it out of Git, so an agent that builds its map from Git, as Aider does, does not list it.
  • Dependencies need your review, because a model can invent a package name. Verify dependencies checks real and invented names.
  • Git commands are yours. A commit says “I read this and I accept it”, and only you can say that. A git reset or an rm can delete work that is not in any commit.
Three nested areas. Inside: the project folder, with four groups of files: may change for the task only (ticket_cleaner and tests), change only when the task changes what they say (README, DECISIONS, docs), read only with review for a change (data, requirements, pyproject, .env.example), never read or change (.env, .venv, reports, .git). Around it: the terminal on this computer, with commands that only read the code (pytest, ruff check, ruff format --check) and commands that change local files (ruff format, the program with --output, git commit). Outside: external services. Three commands cross the outer line: pip install to PyPI, python -m ticket_cleaner remote to the ticket web service, git push to the team's remote repository.
The access boundary of ticket-cleaner, from ASSISTANT-SCOPE.md. The further out an action reaches, the more it needs you: green may run, amber changes files and needs a look at the diff, red needs your decision first.
Text description of the diagram

The diagram has three nested areas. The inner area is the project folder, with four groups of files. ticket_cleaner/.py and tests/.py may change, for the task only. README.md, DECISIONS.md and docs/ change only when the task changes what they say. data/, the requirements files, pyproject.toml and .env.example are read only, and a change needs review. .env, .venv/, reports/ and .git/ are never read or changed. The middle area is the terminal on this computer. Its commands that only read the code may run: python -m pytest, ruff check . and ruff format –check . An arrow labelled “reads” goes from them to the code. Its commands that change local files are ruff format . (review the diff after it), the program with –output reports/…, and git commit, which you run yourself. An arrow labelled “writes” goes from them to the files. The outer area is outside this computer: external services. Three red arrows cross into it. pip install goes to PyPI, the package index. python -m ticket_cleaner remote goes to the ticket web service. git push goes to the team’s remote repository. You review or run these three commands yourself.

A sandbox: a limit that does not depend on the model

Section titled “A sandbox: a limit that does not depend on the model”

The scope file asks. A sandbox enforces. It is a place where a program can do its work but cannot reach what you care about. A child’s sandpit is the picture behind the name: dig as much as you like, and the garden stays as it was.

The course team recorded every session of this course in a simple sandbox. It is a good model for your own work:

A green dashed area, the sandbox: a scratch folder on the author's computer. Inside: a fresh copy of start in a new Git repository; the assistant, Aider, with shell commands off, commits off, and HOME set to the scratch folder; its key, a dummy; a Git box: every change shows in git diff and the copy can be deleted; a logging proxy that adds the real key and writes every request and reply. The assistant edits files in the copy and sends requests through the proxy to the model on Azure, outside the computer. A red box outside the sandbox: the author's own projects, editor and assistant settings, and other keys.
How the course recorded its assistant sessions. The assistant could change only a throwaway copy and never held the real key. It ran no commands, except the tests in the turns that allowed them.
Text description of the diagram

The diagram shows a green dashed area, the sandbox: a scratch folder on the author’s computer. Inside it is a fresh copy of start in a new Git repository, which is easy to compare and to throw away. The assistant, Aider, runs with shell commands and commits turned off. Its home folder is the scratch folder, so it does not read the author’s own settings. It could run the tests only in the few turns that allowed them. Its key is a dummy, not the real key. The assistant edits files in the copy, and every change shows in git diff. Its requests go to a logging proxy, which adds the real key and writes every request and reply to a log. The proxy sends the request to the model on Azure, outside the computer. Outside the sandbox, in red, are the author’s own projects, the editor and assistant settings, and other keys. The assistant cannot reach them.

Each part is a real setting of the recording script, for example --no-suggest-shell-commands and --no-auto-commits. The real key existed only in the proxy, so no transcript and no log contains it.

You can build a simpler sandbox with what you know. Work in a copy, such as ticket-cleaner-assist, never in the only copy of a project. Commit before every session, so that git restore . can undo it. Use the settings of your tool to turn off the commands that you do not want, or to ask before each one. And keep secrets out of the folder and out of the terminal where the assistant runs.

  1. In ~/projects/ticket-cleaner-assist, check the start state:

    Terminal window
    git status

    The output must say On branch feature/category-option and nothing to commit, working tree clean.

  2. Copy the scope file from the snapshot end-of-m01:

    Terminal window
    cp ../nextia-learning-labs/C15/snapshots/end-of-m01/ASSISTANT-SCOPE.md .

    You can also type it yourself from the box above. Then the next step’s check finds any typing error.

  3. Read the file in your editor, one rule at a time. For each rule, say which part it belongs to: files, secrets, commands or external actions.

  4. Commit it:

    Terminal window
    git add ASSISTANT-SCOPE.md
    git commit -m "Write down what an assistant may do in this project"
    git log --oneline
    Output
    [feature/category-option 03e50ea] Write down what an assistant may do in this project
    1 file changed, 52 insertions(+)
    create mode 100644 ASSISTANT-SCOPE.md
    03e50ea Write down what an assistant may do in this project
    245d23e Pin today's report of the sample file
    2498e15 Start

    Your hashes are different.

  5. Run the checks again:

    Terminal window
    python -m pytest
    ruff check .
    ruff format --check .
    Output (the end of each command)
    ============================== 25 passed in 0.04s ==============================
    All checks passed!
    17 files already formatted

    ruff also checks the format of Markdown files, so it counts one file more.

  6. On macOS and Linux, compare your project with the snapshot. Folders that you made yourself, such as .venv, are left out:

    Terminal window
    diff -rq . ../nextia-learning-labs/C15/snapshots/end-of-m01 -x .git -x .venv -x reports -x __pycache__ -x .pytest_cache -x .ruff_cache

    The command prints nothing: your project matches end-of-m01. On Windows, skip this step.

How the assistant gets the file depends on the mode:

  • Chat: paste the parts that matter for the task above the task itself. The chat cannot run commands, so the files and secrets parts matter most.
  • Completion: the scope is for you, while you accept or refuse each suggestion.
  • Agent: add the file to the session as a file to read, not to change. Many agents can also read a project instruction file at the start of every session; your tool’s documentation gives its name. Then use the tool’s settings, so that commands need your approval.

In every mode, the scope stays your checklist. After the session, compare git diff --stat with the files part, and the session’s commands with the commands part.

Write one before the first session in any project, and keep it short: one screen. It takes a few minutes. Update it when the project changes, for example when it gets a new secret or a new command that reaches outside.

A scope has a cost. A strict scope blocks useful work: if the assistant may not change README.md, it cannot document the option that it adds. That is why the file says “when the task changes what they say”, and not “never”. And a scope never makes a change correct. It limits where mistakes can happen; the review in Module 3 finds them.

Common mistake

A secret goes into a prompt

Symptom: a test of the remote input fails with an error from the web service. To get help, you paste the output and your .env file into a chat. The answer is useful. Later, you notice that the real TICKETS_API_TOKEN is in the chat.

Cause: everything that you paste into a chat goes to the provider’s servers. It can stay in your chat history, in the provider’s logs, and in any copy of the conversation that you share. A secret that left your computer is no longer a secret.

Fix: treat the token as leaked. Ask the owner of the service for a new token, and make the old one invalid, even if nothing bad happened yet. Then follow the scope: paste only .env.example, whose values are empty, and replace any real value with a placeholder such as <token>. The settings code in the Python course already keeps the token out of the program’s own output, with field(repr=False).

Module practice: a disposable project with its own scope

Section titled “Module practice: a disposable project with its own scope”

The module’s practice task: prepare a disposable project, and document the scope for one new task. A disposable project is a copy that you can delete at any time. Use it for experiments, and when you try a new assistant.

Your task is this: an assistant will add tests for count_by_category() in report.py, and nothing else.

  1. In ~/projects, copy the snapshot end-of-m01 to a new folder, ticket-cleaner-try.
  2. Make its environment, a Git repository with one commit, and a branch try/tests-only.
  3. Check the baseline: python -m pytest prints 25 passed.
  4. Replace its ASSISTANT-SCOPE.md with a scope for this task only. Use the four parts. Think about which files the assistant may change now, and which it may only read.
  5. Commit the scope. Then delete the folder: it was disposable.
Show an example answer

The commands, on macOS and Linux (on Windows, use Copy-Item -Recurse, python -m venv .venv and .venv\Scripts\Activate.ps1, as in the last lesson):

Terminal window
cd ~/projects
cp -R nextia-learning-labs/C15/snapshots/end-of-m01 ticket-cleaner-try
cd ticket-cleaner-try
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -r requirements-lock.txt
git init
git add -A
git commit -m "Start"
git switch -c try/tests-only
python -m pytest

The last line is 25 passed. One possible scope:

ASSISTANT-SCOPE.md (ticket-cleaner-try)
# What a coding assistant may do in this copy
Task: add tests for `count_by_category()` in `ticket_cleaner/report.py`.
This folder is a disposable copy: I delete it when the task is done.
## Files
| Files | The assistant may |
|---|---|
| `tests/*.py` | read and change them; add a new test file |
| `ticket_cleaner/*.py` | read them only: a test must not change the code |
| `data/`, `README.md`, `requirements*.txt`, `pyproject.toml` | read them only |
| `.env`, `.venv/`, `reports/`, `.git/` | never read or change them |
## Commands
| Command | Rule |
|---|---|
| `python -m pytest`, `ruff check .`, `ruff format --check .` | may run at any time |
| `ruff format tests/` | changes files: I review the diff after it |
| `pip install`, `git commit`, `git push`, `rm` | never: I decide and run them myself |
## Secrets and external actions
No secret is needed for this task. Nothing leaves this computer: no `remote`,
no `pip install`, no push.

Then:

Terminal window
git add ASSISTANT-SCOPE.md
git commit -m "Scope for the tests-only task"
python -m pytest
cd ..
rm -rf ticket-cleaner-try

pytest still prints 25 passed: the scope file changes no code. On Windows, delete the folder with Remove-Item -Recurse -Force ticket-cleaner-try.

The main change from Amira’s file is one line: ticket_cleaner/*.py is now read only. A task “add tests” that changes the code under test is a different task. If the new tests find a bug, the assistant reports it, and you decide what happens next. Your own file can use other words. Check that it has the four parts, and that a reviewer could use it to say “this line of the diff is outside the scope”.

The module’s completion check: say which actions change local files and which affect systems outside your computer. Sort these eight actions into three groups: only reads, changes local files, reaches outside. Some actions belong to two groups.

  1. python -m pytest
  2. ruff format .
  3. python -m ticket_cleaner data/tickets.csv
  4. git commit -m "Add the option"
  5. git restore .
  6. pip install -r requirements-lock.txt
  7. python -m ticket_cleaner remote
  8. git push, and pasting cli.py into a chat window
Show the answer
Action Group Why
python -m pytest only reads it reads the code; Git ignores its cache folder
ruff format . changes local files it rewrites files whose format is wrong: read git diff after it
python -m ticket_cleaner data/tickets.csv changes local files it writes reports/summary.json
git commit changes local files it adds a commit to .git/; nothing leaves the computer
git restore . changes local files it puts back the committed files, and deletes changes that are not committed
pip install -r requirements-lock.txt reaches outside, and changes local files it downloads packages from PyPI, then changes .venv/
python -m ticket_cleaner remote reaches outside, and changes local files it sends a request to the web service, with the token if one is set, then writes the report
git push reaches outside it sends commits to another repository. In the Git course, that was a folder on your computer; in a team, it is a server
pasting cli.py into a chat reaches outside the text goes to the provider’s servers

The scope file puts the second group under review, and the third group under your decision.

You have finished the module when you can also show these on your own project:

  • git log --oneline shows three commits on feature/category-option: Start, Pin today's report of the sample file and Write down what an assistant may do in this project.
  • python -m pytest prints 25 passed, and you can explain what tests/test_baseline.py protects.
  • You can explain each part of ASSISTANT-SCOPE.md, and why a scope file alone is not a lock.

Reset. If your project is broken, rename it and make it again from two snapshots. main gets the course’s start, as in Repository preparation. The branch gets the snapshot of the module that you finished last, in one commit. In ~/projects, on macOS and Linux:

Terminal window
mv ticket-cleaner-assist ticket-cleaner-assist-old
cp -R nextia-learning-labs/C15/snapshots/start ticket-cleaner-assist
cd ticket-cleaner-assist
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -r requirements-lock.txt
git init
git add -A
git commit -m "Start"
git switch -c feature/category-option
cp -R ../nextia-learning-labs/C15/snapshots/end-of-m01/. .
git add -A
git commit -m "Copy the snapshot end-of-m01"
python -m pytest

The last line is 25 passed. Later modules use the same steps, with their own snapshot in the two end-of-m01 places. main always stays at the course’s start, so the pull request in Module 5 shows the whole change.

After a reset, the repository has two commits instead of three: Start on main, and one commit on the branch. The module checks of later modules count the commits of the lesson steps, so after a reset you have fewer. That is fine: the files, the tests and the diff -rq check are what matter.

On Windows, in PowerShell: Rename-Item ticket-cleaner-assist ticket-cleaner-assist-old, then Copy-Item -Recurse nextia-learning-labs\C15\snapshots\start ticket-cleaner-assist. Use python -m venv .venv and .venv\Scripts\Activate.ps1. For the second copy, use Copy-Item -Recurse -Force ..\nextia-learning-labs\C15\snapshots\end-of-m01\* .. The Windows commands are not tested.

Check your understanding

Name the four parts of a scope file, with one rule from ASSISTANT-SCOPE.md for each part.

Show the answer
  • Files: ticket_cleaner/*.py and tests/*.py may change, for the task only; data/ is read only; .env is never read or changed.
  • Secrets: TICKETS_API_TOKEN is only in your terminal or in .env, and never goes into a prompt, a log or a file.
  • Commands: python -m pytest and ruff check . may run at any time. pip install never runs without your review. You run git commit and git push yourself.
  • External actions: the assistant sends nothing outside this computer; the only command that uses the network is remote, and you run it yourself.

Check your understanding

Tomás says: 'We wrote the scope file and gave it to the agent, so now it cannot touch .env.' Is he right? What actually limits an agent?

Show the answer

He is not right. A scope file is text in the prompt, and a model can ignore or misread it. It limits nothing by itself. Two things limit an agent. The first is its tool’s settings, such as no shell commands, or approval before each command. The second is the place where it works: a committed copy of the project, with no secret in the folder or the terminal. That is a sandbox. The scope file still matters: it tells the assistant the limits, and it is your checklist when you review the diff and the session.

Check your understanding

In the refactor-open session, the request 'make the code cleaner' changed write_json() in files.py, and all tests passed. Which line of ASSISTANT-SCOPE.md would a reviewer use to question that change, and why does it matter here?

Show the answer

“Read and change them, for the task only”, and “A change that is not in the task goes into a separate task.” The task was the category option or Grace’s bug, not a new way to write files. write_json() writes every report of the project. So a change there needs its own review and its own tests, even when it looks like an improvement. The passing tests do not answer this: they show only that the tests that exist still pass.

Recap

This lesson

  • The scope of an assistant is what it may read, change and run. ASSISTANT-SCOPE.md writes it down in four parts: files, secrets, commands and external actions.
  • Sort commands into three groups. Some only read (pytest, ruff check .). Some change local files (ruff format ., the report, git commit). Some reach outside (pip install, remote, git push, and a paste into a chat).
  • A scope file asks; a sandbox enforces. The course recorded its sessions in a throwaway copy, with shell commands off and a dummy key.

Module 1: a safe working setup

  • Three modes: chat sees what you paste, completion suggests where you type, and an agent changes files and can run commands. The more it touches, the more you check.
  • A clean starting point: an environment from the lock file, a clean branch on a commit, and baseline checks. A test pins today’s report.
  • Your project matches end-of-m01: three commits on feature/category-option and 25 passed.

Next, in Module 2, you turn Grace’s email into a task that an assistant, or a colleague, can finish and check without guessing.

Next: Problem and acceptance criteria