Conversation
RoniCycode
commented
Apr 9, 2026
- Change "ensure-auth" to "session-start" which includes conversation creation and MCP usage checks (once per session)
| # Step 2: Read stdin payload (backward compat: old hooks pipe no stdin) | ||
| if sys.stdin.isatty(): | ||
| logger.debug('No stdin payload (TTY), skipping session initialization') | ||
| return | ||
|
|
There was a problem hiding this comment.
What it does: sys.stdin.isatty() returns True when stdin is attached to a terminal — i.e. nothing is piped in. If we didn't have this guard, sys.stdin.read() on the next line would block forever waiting
for input that never arrives.
Why it's needed:
- Manual/interactive invocation. If you run cycode ai-guardrails session-start in a shell to debug it, stdin is the terminal. Without this check, the command would hang.
- Backward compat with the old ensure-auth hook. In init.py we kept ensure-auth as a deprecated alias:
app.command(hidden=True, name='ensure-auth', ...)(session_start_command) - Users who installed hooks before this branch have cycode ai-guardrails ensure-auth wired into their IDE config. The old command only ran auth and didn't read stdin. After they upgrade the CLI, that same
hook now invokes session_start_command. The guard ensures that even if the invocation context somehow doesn't provide a JSON payload on stdin, we still do the auth step (which is what the old command did)
and then gracefully skip the conversation/MCP reporting steps instead of hanging.
Flow:
- Hook invoked by IDE → stdin is a pipe → isatty() is False → read JSON, create conversation, report MCP
- Hook invoked with no stdin (manual / edge case) → isatty() is True → auth happens above, then we return early
If you want to make the intent clearer, the comment could be:
- No piped input: would block forever on read(). Happens when run manually,
- or with the legacy
ensure-authhook which didn't supply stdin.
| if ide == AIIDEType.CLAUDE_CODE: | ||
| claude_config = load_claude_config() | ||
| ide_user_email = get_user_email(claude_config) if claude_config else None | ||
| ide_version, _, _ = _extract_from_claude_transcript(payload.get('transcript_path')) |
There was a problem hiding this comment.
do we have a better way to get claude version? i want to get rid of this function and also stop creating conversations for each hook
elsapet
left a comment
There was a problem hiding this comment.
Some comments for your consideration but no major blockers IMO 🙏
| def _get_cursor_session_context() -> tuple[dict, dict]: | ||
| """Return (mcp_servers, enabled_plugins) for Cursor. Cursor has no plugin system.""" | ||
| config = load_cursor_config() | ||
| mcp_servers = get_mcp_servers(config) or {} if config else {} |
There was a problem hiding this comment.
Suggestion to use parens here to make it clearer and less ambiguous. Also, maybe we want to ensure a dict as we do on line 59?
| mcp_servers = get_mcp_servers(config) or {} if config else {} | |
| mcp_servers = dict(get_mcp_servers(config) or {}) if config else {} |
|
|
||
|
|
||
| def _report_session_context(ai_client, ide: str) -> None: | ||
| """Report IDE session context to the AI security manager. Never raises.""" |
There was a problem hiding this comment.
Never raises.
This comment confuses me because there's nothing in the _report_session_context method itself that guarantees this.
If we want to ensure this behaviour here, I would wrap this method logic itself in a try / except block. What do you think?
| return None | ||
|
|
||
|
|
||
| def get_enabled_plugins(settings: dict) -> Optional[dict]: |
There was a problem hiding this comment.
Where is this method used?
| resolve_plugins, | ||
| ) | ||
| from cycode.cli.apps.ai_guardrails.scan.cursor_config import load_cursor_config | ||
| from cycode.cli.apps.ai_guardrails.scan.payload import AIHookPayload, _extract_from_claude_transcript |
There was a problem hiding this comment.
If we're importing _extract_from_claude_transcript here, should we make it a public function?
| app.command(hidden=True, name='session-start', short_help='Handle session start: auth, conversation, session context.')( | ||
| session_start_command | ||
| ) | ||
| app.command(hidden=True, name='ensure-auth', short_help='[Deprecated] Alias for session-start.')( | ||
| session_start_command |
There was a problem hiding this comment.
I assume because these are hidden commands, there are no related documentation updates required 👍
Also, for interest, is it planned to clean up / remove the deprecated command in a later PR?