Skip to content

Add repo-local SDK config support#275

Open
bmdhodl wants to merge 1 commit intocodex/quickstartfrom
codex/repo-config
Open

Add repo-local SDK config support#275
bmdhodl wants to merge 1 commit intocodex/quickstartfrom
codex/repo-config

Conversation

@bmdhodl
Copy link
Copy Markdown
Owner

@bmdhodl bmdhodl commented Mar 27, 2026

Summary

  • add stdlib-only .agentguard.json support for safe repo-local SDK defaults
  • let agentguard.init() and agentguard doctor read the nearest repo config without introducing dashboard coupling
  • document the boundary clearly: local defaults only, no secrets, no API keys, no hosted control-plane behavior

Proof

  • full local suite passed: 564 passed, coverage 93.60%
  • structural tests passed
  • bandit passed
  • real local proof repo written under .codex-proof/repo-config/
  • proof artifacts:
    • .codex-proof/repo-config/doctor.json
    • .codex-proof/repo-config/agent-run.json
    • .codex-proof/repo-config/repo/.agentguard/traces.jsonl
    • .codex-proof/repo-config-pytest-full.txt
    • .codex-proof/repo-config-structural.txt
    • .codex-proof/repo-config-ruff.txt
    • .codex-proof/repo-config-bandit.txt

Notes

@chatgpt-codex-connector
Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds support for a repo-local .agentguard.json file to provide safe, stdlib-only defaults that are automatically picked up by agentguard.init() and agentguard doctor.

Changes:

  • Introduce agentguard.repo_config to discover/load the nearest .agentguard.json and sanitize supported keys (service, trace_file, budget_usd).
  • Wire repo config into agentguard.init() resolution precedence and surface repo config details in agentguard doctor output/JSON.
  • Add tests and docs describing the “local defaults only” boundary and expected precedence (kwargs > env > repo config > defaults).

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
sdk/agentguard/repo_config.py New module to find/load/sanitize repo-local defaults from .agentguard.json.
sdk/agentguard/setup.py Apply repo config as an additional fallback layer in init() config resolution.
sdk/agentguard/doctor.py Include repo config info in doctor payload/output and adjust recommended snippet when repo config exists.
sdk/tests/test_repo_config.py New unit tests for upward discovery, path normalization, key filtering, and validation errors.
sdk/tests/test_init.py Add precedence tests ensuring repo config applies only when kwargs/env are absent.
sdk/tests/test_doctor.py Verify doctor JSON output includes repo config and snippet changes when config is present.
sdk/tests/test_architecture.py Register repo_config.py as a core (stdlib-only) module.
sdk/README.md Document .agentguard.json usage and “no secrets / no hosted settings” boundary.
README.md Top-level docs update mirroring repo-local defaults guidance.
docs/guides/getting-started.md Getting started guide update to include .agentguard.json pattern and minimal init() example.
ops/02-ARCHITECTURE.md Update architecture DAG/docs to include the new repo_config.py module.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +101 to +108
from agentguard.repo_config import load_repo_config

_, repo_config = load_repo_config()

# --- Resolve config: kwargs > env vars > repo config > defaults ---
resolved_key = None if local_only else (api_key or os.environ.get("AGENTGUARD_API_KEY"))
resolved_service = service or os.environ.get("AGENTGUARD_SERVICE", "default")
resolved_file = trace_file or os.environ.get("AGENTGUARD_TRACE_FILE", "traces.jsonl")
resolved_service = service or os.environ.get("AGENTGUARD_SERVICE") or repo_config.get("service") or "default"
resolved_file = trace_file or os.environ.get("AGENTGUARD_TRACE_FILE") or repo_config.get("trace_file") or "traces.jsonl"
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

load_repo_config() is called unconditionally and its exceptions will propagate. This means a malformed/unreadable .agentguard.json can break agentguard.init() even when kwargs/env provide all needed values. Consider only loading repo config when a value is actually missing, or catching OSError/ValueError here and falling back to {} (optionally logging a warning) so repo-local defaults remain non-blocking.

Copilot uses AI. Check for mistakes.
Comment on lines +30 to +35
with open(config_path, encoding="utf-8") as handle:
raw = json.load(handle)

if not isinstance(raw, dict):
raise ValueError(f"{CONFIG_FILE_NAME} must contain a JSON object")

Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

json.load() failures (e.g., invalid JSON) will currently raise json.JSONDecodeError without mentioning which .agentguard.json file was being read. Since this function already normalizes other problems into ValueError, consider catching JSONDecodeError and re-raising ValueError that includes config_path to make diagnostics actionable.

Copilot uses AI. Check for mistakes.
Comment on lines +173 to +177
return "\n".join(
[
"import agentguard",
"",
"agentguard.init()",
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When a repo config is present, _recommended_snippet() returns agentguard.init() without local_only=True. If a user has AGENTGUARD_API_KEY set in their environment, this snippet will send traces to the hosted dashboard (network calls), which can be surprising given doctor’s local-only positioning. Consider keeping local_only=True in the suggested snippet regardless of repo config presence, or emitting a snippet that is explicit about when dashboard mode is intended.

Suggested change
return "\n".join(
[
"import agentguard",
"",
"agentguard.init()",
# When a repo config is present, we still default to local_only=True to avoid
# unexpected network calls. Users can set local_only=False explicitly if they
# want to send traces to the AgentGuard dashboard.
return "\n".join(
[
"import agentguard",
"",
"agentguard.init(",
" local_only=True, # Set to False to send traces to the AgentGuard dashboard.",
")",

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants