How we use AI at PettersonApps — the principles we agree on, how we handle sensitive data, the guardrails we put around AI coding tools, and what to do when something leaks. Written for engineers, used for onboarding.
Short version, for an audience that already knows the fundamentals.
AI is now part of how we build software. This document isn't an introduction to LLMs — it's the set of operational practices we agree to follow so that AI makes us faster without putting client data, security, or our reputation at risk.
It's deliberately practical: data-handling rules, tool guardrails, and runbooks you can act on — plus a short onboarding path for new team members.
Use AI freely to do better work — but a human owns every output, and client & confidential data never touches an unapproved tool. Everything else is detail.
Every specific rule below derives from one of these. When a situation isn't covered, reason from here.
We use AI to speed up routine, data-heavy work and to amplify what people can do. AI is a tool: it doesn't remove responsibility, and it never makes the final decision instead of a person.
Before we build or ship anything that uses AI, we define what harm it could cause if things go wrong. The higher the risk, the more carefully we handle it — we don't skip steps just because we're under pressure.
Internal helpers, drafts, and tools that don't affect clients or money.
Examples: a throwaway script, a README or docs draft, brainstorming, formatting or renaming.
Features clients see, and that influence their decisions.
Examples: customer-facing UI copy, a report a client reads, a recommendation or suggestion feature.
Anything that touches money, safety, legal rights, large volumes of personal data, or can affect many people at once.
Examples: payments and billing, authentication, health/legal/financial outputs, bulk processing of personal data.
As a rule of thumb, the higher the risk, the tighter the leash:
A person with the right knowledge and authority makes the final call and signs off. Whoever ships the system is accountable for the results — including what happens next.
We don't take AI output on faith. Code is run and reviewed, facts are checked, and packages and sources are confirmed to exist. On medium and high risk we also test how the system behaves in unusual and adversarial conditions.
The one rule we never bend. Personal data, client secrets, and our own confidential information are protected by default: we collect only what's actually needed, use it only for the stated purpose, and never send sensitive data to tools that can't guarantee the same level of protection.
Secrets and powerful capabilities are closed by default. Access is opened deliberately, temporarily, and only for the specific task. Agents and tools run with the smallest set of permissions possible.
Code, text, analysis, or decisions produced by AI go through the same reviews, tests, and security checks as if a person wrote them. On high risk the bar is higher — and after release we keep watching how the system behaves.
Inside the team and with clients, we say clearly where AI was used, what exactly it did, and what its known limitations are. Be open with the team when a significant part of the work was AI-generated or heavily assisted — it tells reviewers to look closer, and don't hide AI involvement from clients when it materially affects what we deliver. Where it matters, we keep records so we can later understand why a particular decision was made.
These principles are meant to guide everyday decisions, not to create heavy process.
Applies to every role — engineering, QA, design, PM, sales, ops.
Drafting, boilerplate, refactors, test scaffolding, summarizing, translating, exploring an unfamiliar codebase or API. High-volume, low-ambiguity work.
Anything affecting a client, a person, money, or safety gets human review and sign-off. AI informs the decision; it doesn't make it.
Output is a starting point. Rework it, correct errors, cut filler, and make it fit the real context before it leaves your hands.
Role, goal, constraints, examples, and the output shape you want. Give it the relevant files or references. Vague in, generic out.
Use AI to go faster and learn faster — not to skip understanding. If you can't explain or maintain what it produced, it isn't done. This matters most for juniors: build the fundamentals, use AI as a multiplier on top.
The section that actually matters for a services company handling client code and data.
Assume anything sent to a public AI tool may be retained, logged, or used for training. Only approved tools with clear no-training and zero-retention terms are treated differently. When in doubt, treat it as public.
Right now we use personal accounts (including paid ones). We treat them as public tools and use them with Public data only. For Confidential or Restricted data, don't use AI tools without additional approval — see the classes below.
The four classes are the model; this is the in-the-moment version. Work top to bottom — the first match wins.
.env?Already public: OSS, published docs, marketing copy. Any tool is fine.
Non-sensitive internal material and generic snippets. Approved business-tier tools; avoid free tiers that train on inputs.
Proprietary logic, architecture, financials, roadmaps, non-public personnel data. Approved enterprise tools only, minimized and preferably redacted.
Client source under NDA, credentials, secrets, PII, payment/health data. No AI unless the client approved the specific tool in writing.
.env* in .gitignore, plus a committed .env.example with placeholder keys only.gitleaks, trufflehog, git-secrets) as a required hook so a key never reaches history in the first place.Stop using that chat, don't continue the conversation, and follow the runbook in Section 07 — Leaked Secrets & Rotation. If it was a credential, rotate it.
repos:
- repo: https://github.com/gitleaks/gitleaks
rev: v8.18.0
hooks:
- id: gitleaks # blocks the commit if a secret pattern is found
Our stance on categories. The maintained, named approved-tool list lives with AI Enablement.
| Category | Examples | Status | Condition |
|---|---|---|---|
| Coding assistants (business tier) | Claude / Claude Code, GitHub Copilot, Cursor | Recommended | Org account, training off, deny-list + hooks configured. |
| Chat assistants (business/enterprise) | Claude Team/Enterprise, ChatGPT Team, Gemini for Workspace | Recommended | No-training + retention controls for Internal & above. |
| Free consumer tiers | Free chatbots, browser AI add-ons | Caution | Public data only. May train on inputs. |
| Autonomous agents / broad access | Agents that run commands, edit files, reach prod | Caution | Least privilege, human in loop, never unattended on prod. |
| Unvetted tools & plugins | Unknown extensions, "free GPT" sites, MCP servers of unknown origin | Avoid | No DPA, unclear data handling, supply-chain risk. |
| Any tool on Restricted data | — | Blocked | Unless the client approved that specific tool in writing. |
Found something useful that isn't approved? Don't feed it client or internal data first. Raise it with AI Enablement to vet security, licensing, and data handling — then it's added to the list for everyone. Same due diligence applies to MCP servers and agent integrations.
Don't rely on discipline alone. Make the safe path the default by enforcing it in tooling. Two layers: permissions (declarative) and hooks (programmable).
The same principle applies beyond Claude Code — configure Cursor, Copilot, and internal agents so unsafe actions are blocked by default.
The cheapest guardrail: tell Claude Code it may never read secret files. Add deny rules in .claude/settings.json (commit this so the whole team inherits it):
{
"permissions": {
"deny": [
"Read(./.env)", "Read(./.env.*)",
"Read(./secrets/**)", "Read(**/*.pem)", "Read(**/id_rsa*)"
]
}
}
Hooks run your own shell commands at defined points in the agent loop. Two we recommend: a PreToolUse hook that blocks risky actions before they run, and a PostToolUse hook that scans after edits. A PreToolUse hook that exits with code 2 denies the tool call and feeds its stderr back to Claude as the reason.
{
"hooks": {
"PreToolUse": [
{ "matcher": "Bash",
"hooks": [{ "type": "command",
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/guard-bash.sh" }] }
],
"PostToolUse": [
{ "matcher": "Edit|Write",
"hooks": [{ "type": "command",
"command": "gitleaks protect --staged --no-banner || true" }] }
]
}
}
#!/usr/bin/env bash
# Receives the tool call as JSON on stdin. Exit 2 = deny + return reason to Claude.
input=$(cat)
cmd=$(echo "$input" | jq -r '.tool_input.command // empty')
# Refuse to print or exfiltrate env/secret files
if echo "$cmd" | grep -Eq '(cat|less|head|tail|printenv|env).*(\.env|secret|credential|\.pem|id_rsa)'; then
echo "Blocked: this command would expose secrets. Use the secret manager instead." >&2
exit 2
fi
# Refuse obviously destructive commands
if echo "$cmd" | grep -Eq 'rm -rf (/|~|\$HOME)|git push .*--force.* (main|master)'; then
echo "Blocked: destructive command. Run it manually if you truly intend to." >&2
exit 2
fi
exit 0 # allow everything else
A secret scanner reads diffs and files for high-entropy strings and known key formats (AWS, GCP, Stripe, private keys, and hundreds more) and fails when it finds one. Don't rely on a single choke point — run it wherever a secret could slip through:
PostToolUse hook above runs gitleaks protect --staged right after the model writes code.gitleaks detect), not just the latest diff, to catch anything already committed.Common scanners, all open source and drop-in as a pre-commit or CI step:
protect mode for staged changes. Our default.# fail if a secret is staged (use in a pre-commit / PostToolUse hook)
gitleaks protect --staged --redact --no-banner
# audit everything already committed
gitleaks detect --redact --no-banner
Guardrails move safety from "everyone remembers every time" to "the tool won't let you." Commit the config and hooks to the repo so every engineer — and every AI session — inherits the same rules. Keep hooks fast and fail-safe; a broken hook shouldn't block real work. And remember: a scanner catches leaks, it doesn't undo them — a caught secret that was ever real still needs rotating (Section 07).
Hooks and deny-lists reduce risk; they don't replace judgment or a proper secret manager. Treat them as defense-in-depth, and adapt the patterns above to your stack — these are illustrative starting points, not a drop-in security product.
Coding with assistants like Claude Code, Copilot, and Cursor.
AI writes the first draft; you are the engineer. The moment you commit it, it's your code — it carries the same responsibility, the same review, and the same standard as if you had written every line yourself.
AI can sound confident even when it's wrong — review with that in mind.
If you wouldn't be comfortable explaining the work to a client or in a post-mortem, don't ship it yet.
Use AI to move faster on work you already understand; keep full human control where mistakes are expensive or hard to catch.
A key ended up in a commit, a log, a prompt, or a screenshot. Here's exactly what to do — in order.
A secret that reached a remote, a log, or any third party is compromised — permanently. Deleting the file or rewriting history does not fix it; assume it was scraped within seconds. Rotation is mandatory, not optional. History cleanup only stops future exposure.
Stop the bleeding first. If it's an active credential, disable or scope it down immediately, and revoke any sessions/tokens it issued. Don't wait for the full cleanup.
Generate a new credential in the provider, deploy it via your secret manager, then revoke the old one. New key first, then kill the old — so you don't take down production.
# 1. create the replacement
aws iam create-access-key --user-name svc-app
# 2. update it in the secret manager / deploy, verify the app is healthy
# 3. disable, confirm nothing breaks, then delete the old key
aws iam update-access-key --user-name svc-app --access-key-id AKIA_OLD --status Inactive
aws iam delete-access-key --user-name svc-app --access-key-id AKIA_OLD
Check the provider's audit/access logs and billing for use you didn't authorize between leak and rotation. If the key touched customer data, treat it as a potential data incident and escalate.
Only after rotating. Remove the secret from code, logs, and chat history; where it reached git history, rewrite it to remove the file, then force-push. Coordinate — everyone must re-clone or hard-reset, and open PRs may need rebasing.
# preferred: git-filter-repo
git filter-repo --path .env --invert-paths
# or BFG
bfg --delete-files .env && git reflog expire --expire=now --all && git gc --prune=now
git push --force --all
If it was pushed to a public repo or a fork, also purge caches with the platform (e.g. GitHub support) — but again, this is cleanup, not a substitute for rotation.
Tell your lead / security contact immediately, even for a near-miss. Fast, honest disclosure is what limits damage — and it's explicitly not a blame event. Silence is the only real failure here.
Close the gap that let it happen: add the file to .gitignore, enable the pre-commit secret scanner, wire the Claude Code deny-list and hooks from Section 05, and move the value into the secret manager if it wasn't already.
Same runbook: rotate the credential, delete the conversation, disable chat history/training on that tool, and report it. The paste already happened — rotation is the fix, deletion is just hygiene.
Not every leak has the same impact — a test key isn't a production database credential or an NDA client secret. Still, when in doubt: rotate and report.
The parts that protect us and our clients.
AI can reproduce copyrighted or copyleft code, and ownership of raw AI output can be legally murky. Keep humans meaningfully in the loop so deliverables are clearly ours to license to the client.
Client agreements may restrict or forbid AI, mandate specific tools, or require disclosure. Read them per project — contractual terms override this document.
PII is legally protected (e.g. GDPR). Don't feed it to tools without a DPA covering that use. Anonymize wherever the task allows.
Don't present unverified AI output as certified expert, legal, medical, or financial advice — internally or to clients.
First week for a new team member.
.claude/settings.json deny-list + hooks and the pre-commit secret scanner.We intend to use this technology well — deliberately, securely, and to genuinely raise the quality of what we build. Use AI boldly, verify carefully, guard the data, and ask when unsure.
Practice, not policy. Practical approaches and cases — short notes on how Claude can be used in a manager's daily work: where it helps most often, and where it lets you down. Everything above still applies.
Open as slides → Claude for PMs
Three unread client messages, a follow-up to send after the morning call, and the reflex to paste the company name, the amount and what was discussed into your favourite AI tool. Stop for a second and ask yourself two questions.
Client names, amounts, contacts, NDA notes and anything Restricted do not go into an unapproved tool. Redaction is not a workaround.
One skill for everything: follow-ups, roadmaps, risk analysis, client replies and so on. Sounds convenient, but works poorly — such a skill almost never triggers correctly. Five small skills for specific, repeatable tasks beat one big skill “for every occasion”.
The most common reason a “skill didn't fire”. If the trigger is written in general terms, the model simply doesn't understand when to call it.
If the task isn't repeatable, don't create a skill right away. Start with a prompt. If it sticks and keeps repeating, then it's worth turning into a skill. Otherwise you end up with a folder nobody uses that just takes up space.
The process changed, but the instruction stayed the same, and the model keeps doing things “the old way”. Once a quarter, or as soon as the process changes, check whether the skill still matches reality.
They appear when there are many skills and their descriptions overlap. We write “prepare a report”, and the library has status-report, weekly-report and client-report — the model picks the wrong one. Every skill should state clearly when this one, and not a neighbouring one, should be invoked.
The project says “write in Ukrainian, use this tone”, the skill says something completely different. What comes out isn't always obvious, and the result becomes unpredictable.
A common mistake is to put every detail of projects, clients and access into the skill. A skill is about “how to do it”, not “what to know” — don't add extra information.
Don't put client names, internal links, tokens or any other confidential information into a skill. If the skill goes into the team workspace, that data travels with it. A skill is a public artifact by default.
Imagine a skill not as a text instruction but as a full-blown feature. Nobody ships a feature to production after one lucky click: first it gets checked on different scenarios, edge cases and real data. Treat a skill the same way — take a few real requests, the kind you actually write at work, and check whether the skill responds to them consistently. It's QA, only not for code but for an AI skill.
Why does this matter especially for a manager? A skill in the team workspace immediately starts working for everyone. If it produces a bad result, that's already the whole team's problem. Testing catches it before the team does.
The loop: create the skill → test → see where it fell short → fix → test again. Take 3–5 real requests and run each one twice: with the skill and without it. Compare the results side by side, correct, and repeat until the result is stable and predictable.
Not every skill needs formal evaluation. Do it when you can no longer confidently say “good / bad” by eye, or when the cost of a mistake is high. In other cases a few live checks are enough.
When a decision is complex, it's worth gathering different perspectives — that's what a skill with subagents is for. Instead of one generic answer you get several experts who each examine the same decision from their own side, then converge into a comparison matrix and a recommendation.
Why a skill rather than a prompt in your notes? Copying such a bundle every time is inconvenient; a skill triggers itself. Write “evaluate the decision” and the multi-role breakdown starts right away.
decision-review: each subagent analyses the decision from its own side, then a matrix is compiled, and at the end there's a recommendation.SKILL.md. Otherwise the system won't see the skill, and the subagents remain just a nice idea in a folder.Subagents give several perspectives on a decision. The skill makes sure this bundle switches on by itself whenever we're actually facing a choice.
Turning a subagent into a whole team, where one searches, another writes, and a third checks. A subagent is a separate session that the main model spins up on its own: it gets a specific task, does its part and returns the result. It's easy to confuse with a skill, but a subagent is more like a freelancer — came, did the job, left. A skill is closer to a full-time employee.
There's no point assembling a team to translate a single file.
When several agents work in parallel, it's harder to catch a mistake. This is where a verifier agent helps: one did the work, the other looks at it with fresh eyes, as if it were a colleague's draft. A model checking itself is already defending its own logic; the verifier didn't see how the answer was born, so it's more honest in its pushback. Run it before sending, after research with numbers, after several agents have worked — wherever a mistake is costly. Hallucinations most often hide in dates, prices and names.
Give it the right prompt, and don't tell it the text was written by AI — let it review it as a human's work, without leniency. Its job is to find questionable facts, gaps in logic and missed risks.
The verifier doesn't replace managers, it only narrows the area to check. The final decision must stay with us.
A large part of a manager's work is documents. The same font across eight files, identical headings, tidy metadata — exactly the kind of work you can hand over to AI. But for things to look right in Google Docs, a regular chat is often not enough: you need the Google Docs API. First authorise Google Drive, then grant Claude the access it asks for.
Dropdowns for status or priority and a date picker — the model won't place those properly. The structure and style of templates can be assembled quickly; small interactive bits inside the document still have to be finished by hand.
The team needs a new process explained quickly. You can write a long message, or spend half an hour aligning blocks in Miro — or use Excalidraw: a digital whiteboard where everything looks hand-drawn. Just blocks, arrows and text; the team sees the picture right away instead of a wall of text, and it needs no learning.
It's especially handy when the case is complex and unusual: draw the main path, then add the “what if…” forks together with the team — on a diagram they become visible much faster than in text. It works just as well for architecture, dependencies between tasks or team structure.
You don't draw everything by hand — ask AI to draw your thoughts right inside Claude, with Excalidraw connected via a connector. There's no universal prompt: each time, spell out what exactly you're drawing (a process, a roadmap, team structure, a flow), which blocks or steps should be there, how they're connected, and how detailed it should be. The diagram isn't a static image — edit it by hand, or ask AI to look again and analyse exactly the points that matter.
You get the result fast, so you can both explain and immediately see the weak spots.
Set up the Figma connector as usual: find Figma in the connector settings, log in and restart the session. The manager's job is to check the completeness of the screens and their compliance. After the review, three things should be clear: does the mockup solve the task we set, is everything development needs drawn, and has anything extra appeared that has neither an agreement nor a budget?
Does the mockup solve the user's problem at all?
Are all screens and scenarios in place, and has nothing extra been drawn?
Empty screen, loading, error, long text, zero items and ten thousand items.
Tokens instead of “freehand” colours, components from the library, identical spacing.
AI can't fully close the first two tasks — it doesn't know the requirements until we give them. But states and systematic issues it often catches faster than a human: the eye easily misses the difference between 16 and 18 pixels; the model doesn't.
AI can see and analyse screens, layer structure, tokens, library components, comments, sometimes even animations and FigJam. A prototype also works, with limitations: AI clicks on the image, sometimes misses, ends the session quickly on a long flow, and can't tell a prototype bug from intent. It won't feel that a screen is overloaded, but it also won't get lost where a real person would.
Run a short check with AI: are all states there, are the texts final, are icons and logos in place, are layers named the way they should be.
An AI review is a draft that the manager checks and signs off — it shouldn't be forwarded to the designer without a look.