The Agent Secrets Pattern: Giving AI Access Without Git Exposure

Cover Image for The Agent Secrets Pattern: Giving AI Access Without Git Exposure
Mario Giancini
Mario Giancini
@MarioGiancini
Published:
Read Time: 4 min

I stumbled on this pattern while building automation commands for Claude Code and Cursor.

The problem: my AI agents needed credentials for browser automation, but I obviously couldn't commit those credentials to git.

The best practice for keys and credentials is .env, or environment variables, but using that would create a new problem.

My app's .env has database URLs, API keys, and other runtime secrets. Mixing automation credentials in there felt off. And more practically, the .env lived in a subproject directory, which made the path awkward for workspace-level commands.

Cursor added another layer of complexity because it can't read .env files directly.

I needed a better solution.

The Pattern: A Dedicated .agent-secrets File

project/
├── .agent-secrets.example   # Template (committed)
├── .agent-secrets           # Your credentials (gitignored)
├── .gitignore               # Blocks .agent-secrets from git
├── .cursorignore            # Allows .agent-secrets for Cursor
└── .claude/
    └── settings.local.json  # Grants explicit read access for Claude Code

The key insight: both Claude Code and Cursor need explicit configuration to read gitignored files.

By default, they respect .gitignore for security. When you need to, you can grant access to specific files.

Configuring Claude Code

Claude Code respects .gitignore for search operations, but it can read files directly if you grant explicit permission.

Add this to .claude/settings.local.json:

{
  "permissions": {
    "allow": [
      "Read(.agent-secrets)"
    ]
  }
}

Now Claude Code can read .agent-secrets without prompting, while the file stays out of your commits.

Configuring Cursor

Cursor blocks access to gitignored files by default. This is a security feature. It also has global ignore patterns that block .env files automatically.

To allow Cursor to read .agent-secrets, create a .cursorignore file with a negation pattern:

# .cursorignore
# Allow agent secrets (overrides gitignore)
!.agent-secrets

The ! prefix tells Cursor to include this file even though it's in .gitignore.

Without this, Cursor's Agent, Tab, and Inline Edit features won't have access to your credentials.

The File Format

Keep it simple. No JSON, no YAML. Just key-value pairs:

# .agent-secrets.example
# Agent Automation Secrets
# Copy to .agent-secrets and fill in values

# LinkedIn Browser Automation
LINKEDIN_EMAIL=
LINKEDIN_PASSWORD=

# Other browser automation credentials can go here

The .example file gets committed. The actual .agent-secrets file with your credentials stays local.

Why Separation Matters

This isn't just about organization.

It's about the principle of least privilege applied to AI agents.

Your app's .env might contain:

  • Database connection strings
  • Payment processor keys
  • Admin API tokens

Your agent doesn't need any of that to log into LinkedIn and scrape a profile.

By separating agent credentials, you:

  1. Reduce attack surface: If an agent leaks context, it only has automation credentials
  2. Simplify auditing: One file, one purpose, easy to review
  3. Enable workspace-level access: Credentials live at project root, not buried in subprojects

Command Integration

In your custom commands, reference the file explicitly:

### Step 3: Login Check
If LinkedIn shows a login wall, read credentials:
\`\`\`bash
cat .agent-secrets 2>/dev/null | grep -E "LINKEDIN_EMAIL|LINKEDIN_PASSWORD"
\`\`\`
Or use ReadFile on `.agent-secrets` directly.

The agent knows exactly where to look. No searching, no guessing.

The Broader Pattern

This approach aligns with established security practices:

PrincipleApplication
Centralized ManagementOne file for all agent credentials
Environment SegmentationApp secrets vs agent secrets
Least PrivilegeAgents only access what they need
Defense in DepthGitignored AND explicitly scoped

For larger teams or production environments, you'd layer this with proper secret management (HashiCorp Vault, AWS Secrets Manager).

But for solo developers and small teams, the pattern provides meaningful security without operational overhead.

The Decision Framework

Before adding credentials to .agent-secrets, ask:

  1. Does the agent actually need this? Only include what's required.
  2. Could this be a read-only token? Prefer minimal permissions.
  3. Is this documented? Keep .example updated.
  4. Is there a fallback? "Ask user to log in manually" if credentials are missing.

Implementation Checklist

# 1. Create the template
touch .agent-secrets.example
# Add your variable names (no values)

# 2. Create your actual file
cp .agent-secrets.example .agent-secrets
# Fill in your credentials

# 3. Gitignore it
echo ".agent-secrets" >> .gitignore

# 4. Grant Claude Code access (if using)
# Add Read(.agent-secrets) to .claude/settings.local.json

# 5. Grant Cursor access (if using)
echo "!.agent-secrets" >> .cursorignore

# 6. Document it
# Add section to CLAUDE.md or README

If you're navigating the intersection of AI tooling and security, I'd love to hear your approach.


Did you find this article useful?

Subscribe to my newsletter for more content like this.


Related Posts

View All →