Using a Per-Project .env Config File in last30days-skill: Complete Setup Guide
The last30days-skill framework automatically discovers .claude/last30days.env files by walking up the directory tree from your current working directory, merging per-project settings with global configuration while always allowing environment variables to take precedence.
Managing API keys and feature flags across multiple projects becomes cumbersome when relying solely on global environment variables. The last30days-skill repository solves this by supporting a per-project .env config file that lives alongside your code, ensuring credentials stay portable and version-controllable without polluting your system-wide configuration. This approach uses a hierarchical loading system where project-specific values override global settings while remaining subservient to shell-level environment overrides.
Configuration Priority Hierarchy
The configuration system in scripts/lib/env.py implements a three-tier precedence model:
- Environment variables (
os.environ) — Highest priority, checked first viaos.getenv - Per-project file (
.claude/last30days.env) — Discovered dynamically, overrides global settings - Global file (
~/.config/last30days/.env) — Lowest priority, loaded fromCONFIG_FILE
When get_config() builds the final dictionary, it resolves each key using os.environ.get(...) or merged_env.get(...), ensuring environment variables automatically supersede both file-based sources.
How Per-Project Discovery Works
The framework locates your project configuration through directory traversal rather than fixed paths.
The Discovery Algorithm
When scripts/last30days.py invokes env.get_config() (lines 37-38), the following occurs in scripts/lib/env.py:
- Directory walking:
_find_project_env()(lines 198-211) walks upward from the current working directory through each parent directory - File detection: It searches for
.claude/last30days.envin every directory level - Parsing: Upon finding the file,
load_env_file(lines 66-87) parses key-value pairs into a dictionary - Merging: Project values override the global configuration loaded from
~/.config/last30days/.env - Final resolution: The configuration dictionary populates each key using environment variables first, then merged file values
This algorithm ensures that running the skill from any subdirectory of your project still locates the root configuration file.
Creating a Per-Project .env Config File
Place your configuration at the project root using the required path structure:
your-project/
├── .claude/
│ └── last30days.env
└── src/
The file supports standard environment variable syntax:
OPENAI_API_KEY=sk-xxxx-your-key
BRAVE_API_KEY=brave-key-123
XAI_API_KEY=xai-key-abc
GEMINI_API_KEY=gemini-key-def
BSKY_HANDLE=alice.bsky.social
BSKY_APP_PASSWORD=super-secret-pw
Only define the keys required for that specific project. Missing keys automatically fall back to the global file or environment variables according to the precedence hierarchy.
Practical Usage Examples
Running the Skill from a Project Directory
Execute commands from any subdirectory of your repository:
cd ~/projects/news-analysis
python3 scripts/last30days.py "AI in education" --emit=compact
Because scripts/last30days.py calls env.get_config() at lines 37-38, the per-project file loads automatically before any API calls execute.
Accessing Configuration in Custom Code
Import the environment module to retrieve parsed values:
from lib import env
cfg = env.get_config()
print("OpenAI key:", cfg["OPENAI_API_KEY"])
# Prints value from .claude/last30days.env unless overridden by shell variable
Overriding for Single Runs
Temporarily bypass project settings using shell exports:
OPENAI_API_KEY=sk-override-123 python3 scripts/last30days.py "Quantum computing"
The exported value supersedes both per-project and global file configurations immediately.
Testing the Configuration Behavior
The repository includes tests/test_env_project.py to certify the loading logic. This test suite validates:
- Directory traversal correctly discovers project files
- Project values override global configuration
- Environment variables override project values
_CONFIG_SOURCEaccurately reports the configuration origin (project, global, or environment)
Run the validation suite:
pytest -q tests/test_env_project.py
Summary
- Per-project .env files in
last30days-skilluse the path.claude/last30days.envdiscovered by walking up the directory tree - Configuration priority follows: Environment variables > Per-project file > Global file (
~/.config/last30days/.env) - Core implementation resides in
scripts/lib/env.py, specifically_find_project_env()(lines 198-211) andget_config() - Automatic loading occurs when
scripts/last30days.pyinitializes viaenv.get_config()(lines 37-38) - Override capability allows temporary environment variables to supersede file-based configuration for debugging or secrets management
Frequently Asked Questions
Where should I place the per-project .env config file?
Create a directory named .claude in your project root and place the file last30days.env inside it. The _find_project_env() function in scripts/lib/env.py searches for this specific path while walking upward from your current working directory, allowing the skill to find configuration even when run from subdirectories.
Can I use a per-project config file alongside global configuration?
Yes. The system merges both sources, with the per-project file at .claude/last30days.env overriding values from the global ~/.config/last30days/.env. You can define common defaults globally and project-specific overrides locally, reducing duplication while maintaining flexibility.
How do I temporarily override a value from my per-project file without editing it?
Export the variable in your shell before running the command. The configuration resolution logic in scripts/lib/env.py checks os.environ before falling back to file-based values, so OPENAI_API_KEY=sk-new-key python3 scripts/last30days.py "query" immediately supersedes any file-stored API key for that single execution.
Does the skill tell me which configuration source it used?
Yes. The get_config() function populates a _CONFIG_SOURCE field in the returned dictionary indicating whether values originated from the project file, global file, or environment only. This metadata field helps debug configuration precedence issues when multiple sources define the same keys.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →