Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 53 additions & 66 deletions QUICK_START_LOGGING.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
## ⚡ TL;DR - 3 Step Process

1. **Import the logger**: `from codegen.shared.logging.get_logger import get_logger`
2. **Add `extra={}` to your log calls**: `logger.info("message", extra={"key": "value"})`
3. **Enable telemetry**: `codegen config telemetry enable`
1. **Add `extra={}` to your log calls**: `logger.info("message", extra={"key": "value"})`
1. **Enable telemetry**: `codegen config telemetry enable`
Comment on lines 5 to +7

Choose a reason for hiding this comment

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

medium

The numbered list for the "3 Step Process" is incorrect. All items are numbered as 1.. For a correctly rendered ordered list, they should be numbered sequentially (1., 2., 3.).

Suggested change
1. **Import the logger**: `from codegen.shared.logging.get_logger import get_logger`
2. **Add `extra={}` to your log calls**: `logger.info("message", extra={"key": "value"})`
3. **Enable telemetry**: `codegen config telemetry enable`
1. **Add `extra={}` to your log calls**: `logger.info("message", extra={"key": "value"})`
1. **Enable telemetry**: `codegen config telemetry enable`
1. **Import the logger**: `from codegen.shared.logging.get_logger import get_logger`
2. **Add `extra={}` to your log calls**: `logger.info("message", extra={"key": "value"})`
3. **Enable telemetry**: `codegen config telemetry enable`


**That's it!** Your logs automatically go to Grafana Cloud when telemetry is enabled.

Expand All @@ -22,11 +22,14 @@ from codegen.shared.logging.get_logger import get_logger
logger = get_logger(__name__)

# Find any existing console.print() or error handling and add:
logger.info("Operation completed", extra={
"operation": "command_name",
"org_id": org_id, # if available
"success": True
})
logger.info(
"Operation completed",
extra={
"operation": "command_name",
"org_id": org_id, # if available
"success": True,
},
)
```

### 2. Test the Integration Right Now
Expand All @@ -38,7 +41,7 @@ codegen config telemetry enable
# 2. Run the demo
python example_enhanced_agent_command.py

# 3. Run any CLI command
# 3. Run any CLI command
codegen agents # or any other command

# 4. Check status
Expand All @@ -48,69 +51,56 @@ codegen config telemetry status
## 📝 Copy-Paste Patterns

### Pattern 1: Operation Start/End

```python
logger = get_logger(__name__)

# At start of function
logger.info("Operation started", extra={
"operation": "command.subcommand",
"user_input": relevant_input
})

# At end of function
logger.info("Operation completed", extra={
"operation": "command.subcommand",
"success": True
})
logger.info("Operation started", extra={"operation": "command.subcommand", "user_input": relevant_input})

# At end of function
logger.info("Operation completed", extra={"operation": "command.subcommand", "success": True})
Comment on lines 58 to +62

Choose a reason for hiding this comment

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

medium

The logger calls in this example have been condensed to a single line. For calls with multiple parameters in the extra dictionary, the previous multi-line format was more readable and is used in other examples within this same file (e.g., lines 25-32). For consistency and improved readability, consider reverting to the multi-line format for these examples.

Suggested change
# At start of function
logger.info("Operation started", extra={
"operation": "command.subcommand",
"user_input": relevant_input
})
# At end of function
logger.info("Operation completed", extra={
"operation": "command.subcommand",
"success": True
})
logger.info("Operation started", extra={"operation": "command.subcommand", "user_input": relevant_input})
# At end of function
logger.info("Operation completed", extra={"operation": "command.subcommand", "success": True})
# At start of function
logger.info("Operation started", extra={
"operation": "command.subcommand",
"user_input": relevant_input
})
# At end of function
logger.info("Operation completed", extra={
"operation": "command.subcommand",
"success": True
})

```

### Pattern 2: Error Handling

```python
try:
# your existing code
pass
except SomeSpecificError as e:
logger.error("Specific error occurred", extra={
"operation": "command.subcommand",
"error_type": "specific_error",
"error_details": str(e)
}, exc_info=True)
logger.error("Specific error occurred", extra={"operation": "command.subcommand", "error_type": "specific_error", "error_details": str(e)}, exc_info=True)
# your existing error handling
```

### Pattern 3: API Calls

```python
# Before API call
logger.info("Making API request", extra={
"operation": "api.request",
"endpoint": "agent/run",
"org_id": org_id
})
logger.info("Making API request", extra={"operation": "api.request", "endpoint": "agent/run", "org_id": org_id})

# After successful API call
logger.info("API request successful", extra={
"operation": "api.request",
"endpoint": "agent/run",
"response_id": response.get("id"),
"status_code": response.status_code
})
logger.info("API request successful", extra={"operation": "api.request", "endpoint": "agent/run", "response_id": response.get("id"), "status_code": response.status_code})
Copy link

@cubic-dev-ai cubic-dev-ai bot Sep 12, 2025

Choose a reason for hiding this comment

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

response.get(...) conflicts with response.status_code; use response.json().get("id") to access the JSON id from a requests.Response

Prompt for AI agents
Address the following comment on QUICK_START_LOGGING.md at line 83:

<comment>response.get(...) conflicts with response.status_code; use response.json().get(&quot;id&quot;) to access the JSON id from a requests.Response</comment>

<file context>
@@ -48,69 +51,56 @@ codegen config telemetry status
-    &quot;response_id&quot;: response.get(&quot;id&quot;),
-    &quot;status_code&quot;: response.status_code
-})
+logger.info(&quot;API request successful&quot;, extra={&quot;operation&quot;: &quot;api.request&quot;, &quot;endpoint&quot;: &quot;agent/run&quot;, &quot;response_id&quot;: response.get(&quot;id&quot;), &quot;status_code&quot;: response.status_code})
 ```
 
</file context>
Suggested change
logger.info("API request successful", extra={"operation": "api.request", "endpoint": "agent/run", "response_id": response.get("id"), "status_code": response.status_code})
logger.info("API request successful", extra={"operation": "api.request", "endpoint": "agent/run", "response_id": response.json().get("id"), "status_code": response.status_code})
Fix with Cubic

```
Comment on lines 79 to 84
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix incorrect Response usage in example

requests.Response doesn’t support .get(...). Use response.json().get(...) or the parsed dict.

-logger.info("API request successful", extra={"operation": "api.request", "endpoint": "agent/run", "response_id": response.get("id"), "status_code": response.status_code})
+logger.info(
+    "API request successful",
+    extra={
+        "operation": "api.request",
+        "endpoint": "agent/run",
+        "response_id": response.json().get("id"),
+        "status_code": response.status_code,
+    },
+)

Optionally align this with the agent example that assigns agent_run_data = response.json().

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Before API call
logger.info("Making API request", extra={
"operation": "api.request",
"endpoint": "agent/run",
"org_id": org_id
})
logger.info("Making API request", extra={"operation": "api.request", "endpoint": "agent/run", "org_id": org_id})
# After successful API call
logger.info("API request successful", extra={
"operation": "api.request",
"endpoint": "agent/run",
"response_id": response.get("id"),
"status_code": response.status_code
})
logger.info("API request successful", extra={"operation": "api.request", "endpoint": "agent/run", "response_id": response.get("id"), "status_code": response.status_code})
```
# Before API call
logger.info("Making API request", extra={"operation": "api.request", "endpoint": "agent/run", "org_id": org_id})
# After successful API call
logger.info(
"API request successful",
extra={
"operation": "api.request",
"endpoint": "agent/run",
"response_id": response.json().get("id"),
"status_code": response.status_code,
},
)
🤖 Prompt for AI Agents
In QUICK_START_LOGGING.md around lines 79 to 84, the example incorrectly calls
response.get(...) on a requests.Response object; parse the JSON first (e.g.,
agent_run_data = response.json()) or call response.json().get(...) and then use
that parsed dict for response_id and any other fields so the logging example
uses a dict (response_id = agent_run_data.get("id")) instead of
response.get(...).


## 🎯 What to Log (Priority Order)

### 🔥 High Priority (Add These First)

- **Operation start/end**: When commands begin/complete
- **API calls**: Requests to your backend
- **Authentication events**: Login/logout/token issues
- **Authentication events**: Login/logout/token issues
- **Errors**: Any exception or failure
- **User actions**: Commands run, options selected

### ⭐ Medium Priority

- **Performance**: Duration of operations
- **State changes**: Status updates, configuration changes
- **External tools**: Claude CLI detection, git operations

### 💡 Low Priority (Nice to Have)

- **Debug info**: Internal state, validation steps
- **User behavior**: Which features are used most

Expand All @@ -126,30 +116,30 @@ logger = get_logger(__name__)

def create(prompt: str, org_id: int | None = None, ...):
"""Create a new agent run with the given prompt."""

# ADD: Log start
logger.info("Agent creation started", extra={
"operation": "agent.create",
"org_id": org_id,
"prompt_length": len(prompt)
})

# Your existing code...
try:
response = requests.post(url, headers=headers, json=payload)
agent_run_data = response.json()
# ADD: Log success

# ADD: Log success
logger.info("Agent created successfully", extra={
"operation": "agent.create",
"agent_run_id": agent_run_data.get("id"),
"status": agent_run_data.get("status")
})

except requests.RequestException as e:
# ADD: Log error
logger.error("Agent creation failed", extra={
"operation": "agent.create",
"operation": "agent.create",
"error_type": "api_error",
"error": str(e)
})
Expand All @@ -163,52 +153,49 @@ def create(prompt: str, org_id: int | None = None, ...):

logger = get_logger(__name__)


def _run_claude_interactive(resolved_org_id: int, no_mcp: bool | None) -> None:
session_id = generate_session_id()

# ADD: Log session start
logger.info("Claude session started", extra={
"operation": "claude.session_start",
"session_id": session_id[:8], # Short version for privacy
"org_id": resolved_org_id
})

logger.info(
"Claude session started",
extra={
"operation": "claude.session_start",
"session_id": session_id[:8], # Short version for privacy
"org_id": resolved_org_id,
},
)

# Your existing code...

try:
process = subprocess.Popen([claude_path, "--session-id", session_id])
returncode = process.wait()

# ADD: Log session end
logger.info("Claude session completed", extra={
"operation": "claude.session_complete",
"session_id": session_id[:8],
"exit_code": returncode,
"status": "COMPLETE" if returncode == 0 else "ERROR"
})

logger.info(
"Claude session completed", extra={"operation": "claude.session_complete", "session_id": session_id[:8], "exit_code": returncode, "status": "COMPLETE" if returncode == 0 else "ERROR"}
)

except Exception as e:
# ADD: Log session error
logger.error("Claude session failed", extra={
"operation": "claude.session_error",
"session_id": session_id[:8],
"error": str(e)
})
logger.error("Claude session failed", extra={"operation": "claude.session_error", "session_id": session_id[:8], "error": str(e)})
```

## 🧪 Verification

After making changes:

1. **Run the command**: Execute your enhanced CLI command
2. **Check telemetry status**: `codegen config telemetry status`
3. **Look for logs in Grafana Cloud**: Search for your operation names
4. **Test with telemetry disabled**: `codegen config telemetry disable` - should still work normally
1. **Check telemetry status**: `codegen config telemetry status`
1. **Look for logs in Grafana Cloud**: Search for your operation names
1. **Test with telemetry disabled**: `codegen config telemetry disable` - should still work normally
Comment on lines 190 to +193

Choose a reason for hiding this comment

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

medium

The numbered list under the "Verification" section is incorrect. All items are numbered as 1., which will not render as a sequential list.

Suggested change
1. **Run the command**: Execute your enhanced CLI command
2. **Check telemetry status**: `codegen config telemetry status`
3. **Look for logs in Grafana Cloud**: Search for your operation names
4. **Test with telemetry disabled**: `codegen config telemetry disable` - should still work normally
1. **Check telemetry status**: `codegen config telemetry status`
1. **Look for logs in Grafana Cloud**: Search for your operation names
1. **Test with telemetry disabled**: `codegen config telemetry disable` - should still work normally
1. **Run the command**: Execute your enhanced CLI command
2. **Check telemetry status**: `codegen config telemetry status`
3. **Look for logs in Grafana Cloud**: Search for your operation names
4. **Test with telemetry disabled**: `codegen config telemetry disable` - should still work normally


## 🚀 Progressive Enhancement

**Week 1**: Add basic operation logging to 2-3 commands
**Week 2**: Add error logging to all commands
**Week 2**: Add error logging to all commands
**Week 3**: Add performance metrics and detailed context
**Week 4**: Create Grafana dashboards using the collected data

Expand Down
7 changes: 6 additions & 1 deletion docs/docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,12 @@
},
{
"group": "Settings",
"pages": ["settings/repo-rules", "settings/model-configuration"]
"pages": [
"settings/repo-rules",
"settings/model-configuration",
"settings/team-roles",
"settings/agent-permissions"
]
}
]
},
Expand Down
111 changes: 111 additions & 0 deletions docs/settings/team-roles.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
---
title: "Team Member Roles"
sidebarTitle: "Team Roles"
icon: "users"
---

Team member roles control what actions users can perform within your Codegen organization. The role system uses a hierarchical permission model to ensure proper access control while allowing teams to delegate responsibilities appropriately.

## Role Hierarchy

There are **three roles** in the system with a hierarchical structure where higher roles inherit all permissions from lower roles:

`MEMBER` < `MANAGER` < `ADMIN`

## Role Definitions

### 🔴 **ADMIN** (Highest Level)

Admins have **full administrative access** to the organization and can perform all actions:

- **Manage billing** and subscription settings
- **Delete repositories** (only admins can do this)
- **Change user roles** (promote/demote team members)
- **Manage integrations** (GitHub, Linear, Slack, etc.)
- **Access organization settings**
- **View cost breakdowns and analytics**
- **Invite users to the organization**

### 🟡 **MANAGER** (Middle Level)

Managers have operational permissions but lack administrative controls:

- **Manage integrations** (GitHub, Linear, Slack, etc.)
- **View and manage organization integrations**
Comment on lines +33 to +34
Copy link

Choose a reason for hiding this comment

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

Duplicate Integration Management Permission category Readability

Tell me more
What is the issue?

Redundant permission listed for Manager role. 'Manage integrations' and 'View and manage organization integrations' describe the same functionality.

Why this matters

Listing the same permission twice in different words can cause confusion about whether these are distinct capabilities, potentially leading to misunderstandings about the role's actual permissions.

Suggested change ∙ Feature Preview

Remove one of the redundant entries. Keep only:

- **Manage integrations** (GitHub, Linear, Slack, etc.)
Provide feedback to improve future suggestions

Nice Catch Incorrect Not in Scope Not in coding standard Other

💬 Looking for more details? Reply to this comment to chat with Korbit.

- **Cannot** access billing information
- **Cannot** manage user roles
- **Cannot** delete repositories

### 🟢 **MEMBER** (Basic Level)

Members have basic permissions for day-to-day work:

- **View agent traces and runs**
- **Use main application features** (creating agents, viewing repos, etc.)
- **View their own profile and settings**
- **Cannot** manage integrations
- **Cannot** access billing information
- **Cannot** manage other users
- **Cannot** delete repositories

## Permission Matrix

| Feature | Member | Manager | Admin |
|---------|--------|---------|-------|
| View repositories ||||
| Create and run agents ||||
| View agent traces ||||
| Manage integrations ||||
| Delete repositories ||||
| Access billing ||||
| Change user roles ||||
| Organization settings | Limited | Limited | Full |
Copy link

Choose a reason for hiding this comment

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

Ambiguous Organization Settings Access category Functionality

Tell me more
What is the issue?

The permission matrix shows 'Limited' access for both Member and Manager roles without specifying what 'Limited' means.

Why this matters

Without clear definition of 'Limited' access, users won't understand what organization settings they can actually access, potentially leading to confusion or access-related issues.

Suggested change ∙ Feature Preview

Either define what 'Limited' means or be specific about the exact permissions in the matrix:

| Organization settings | View Only | View & Edit Basic | Full |
Provide feedback to improve future suggestions

Nice Catch Incorrect Not in Scope Not in coding standard Other

💬 Looking for more details? Reply to this comment to chat with Korbit.

| Invite users ||||

## Managing Team Roles

### Default Role Assignment

- New team members are assigned the **MEMBER** role by default
- This ensures new users have basic access without administrative privileges

### Changing Roles

Only **ADMIN** users can promote or demote other team members:

1. Navigate to your organization's team management page
2. Find the user whose role you want to change
3. Select the new role from the dropdown
4. Confirm the change

### Role Restrictions

- You cannot assign a role higher than your own
- The system prevents privilege escalation attacks
- At least one ADMIN must remain in each organization

## Best Practices

### Security Considerations

- **Principle of Least Privilege**: Assign the minimum role necessary for each team member's responsibilities
- **Regular Audits**: Periodically review team member roles and adjust as needed
- **Onboarding**: Start new team members as MEMBER and promote as they gain experience

### Role Assignment Guidelines

- **MEMBER**: Developers, contractors, or team members who primarily work with code and agents
- **MANAGER**: Team leads, project managers, or senior developers who need to manage integrations
- **ADMIN**: Organization owners, DevOps engineers, or senior leadership who need full control
Comment on lines +98 to +99
Copy link

Choose a reason for hiding this comment

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

Vague ADMIN role assignment criteria category Documentation

Tell me more
What is the issue?

The Role Assignment Guidelines lack specifics about when to grant ADMIN access, which could lead to overprivileged accounts.

Why this matters

Overly broad ADMIN role assignments increase security risks and complicate access management.

Suggested change ∙ Feature Preview
  • MANAGER: Team leads, project managers, or senior developers who need to manage integrations
  • ADMIN: Organization owners or designated security leads - limit to 2-3 trusted individuals per organization
Provide feedback to improve future suggestions

Nice Catch Incorrect Not in Scope Not in coding standard Other

💬 Looking for more details? Reply to this comment to chat with Korbit.


### Workflow Integration

- Consider your team's structure when assigning roles
- Ensure critical functions (billing, user management) are accessible to multiple admins
- Document role assignments and responsibilities for your team

## Related Documentation

- [Agent Permissions](/settings/agent-permissions) - Configure what actions agents can perform
- [Organization Rules](/settings/organization-rules) - Set organization-wide rules

Choose a reason for hiding this comment

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

medium

The link to [Organization Rules](/settings/organization-rules) appears to be broken. The docs/docs.json file does not list an organization-rules page under settings, but it does list repo-rules. Please verify the correct link target.

- [Repository Rules](/settings/repo-rules) - Configure repository-specific behavior

- [Repository Rules](/settings/repo-rules) - Configure repository-specific behavior
Comment on lines +109 to +111
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Broken/undeclared link: Organization Rules

/settings/organization-rules isn’t in docs.json navigation. Either add the page to docs/docs.json or update the link to an existing page.

Run:


🏁 Script executed:

#!/bin/bash
fd -a 'organization-rules.*' docs || true
jq -r '.navigation.tabs[0].groups[]?|select(.group=="Settings")|.pages' docs/docs.json

Length of output: 174


Add missing navigation entry: Organization Rules

docs/settings/team-roles.mdx (lines 109–111) links to /settings/organization-rules; docs/settings/organization-rules.mdx exists but "settings/organization-rules" is not listed in docs/docs.json (navigation.tabs[0].groups[] where group == "Settings"). Add "settings/organization-rules" to that pages array or update the link to an existing page.

🤖 Prompt for AI Agents
In docs/settings/team-roles.mdx around lines 109 to 111 the page links to
/settings/organization-rules but the route "settings/organization-rules" is
missing from the documentation navigation; open docs/docs.json, locate
navigation.tabs[0].groups[] item where group == "Settings" and add
"settings/organization-rules" to that group's pages array (or alternatively
change the link in team-roles.mdx to an existing listed page); ensure the path
string matches the existing routing format used elsewhere in docs.json.

1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ dependencies = [
"unidiff>=0.7.5",
"datamodel-code-generator>=0.26.5",
"fastmcp>=2.9.0",
"mcp-python>=0.1.4",
# OpenTelemetry logging dependencies
"opentelemetry-api>=1.26.0",
"opentelemetry-sdk>=1.26.0",
Expand Down
2 changes: 2 additions & 0 deletions src/codegen/cli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from codegen.cli.commands.integrations.main import integrations_app
from codegen.cli.commands.login.main import login
from codegen.cli.commands.logout.main import logout
from codegen.cli.commands.mcp.main import mcp
from codegen.cli.commands.org.main import org
from codegen.cli.commands.profile.main import profile_app
from codegen.cli.commands.repo.main import repo
Expand Down Expand Up @@ -65,6 +66,7 @@ def version_callback(value: bool):
main.command("init", help="Initialize or update the Codegen folder.")(init)
main.command("login", help="Store authentication token.")(login)
main.command("logout", help="Clear stored authentication token.")(logout)
main.command("mcp", help="Start the Codegen MCP server.")(mcp)
main.command("org", help="Manage and switch between organizations.")(org)
main.command("repo", help="Manage repository configuration and environment variables.")(repo)
main.command("style-debug", help="Debug command to visualize CLI styling (spinners, etc).")(style_debug)
Expand Down
1 change: 0 additions & 1 deletion src/codegen/cli/commands/claude/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
"""Claude Code integration commands."""

Loading