Safe GitLab Writer¶
Review-gated writing system that ensures all automated documentation changes go through feature branches and merge requests.
Overview¶
The Safe GitLab Writer prevents direct commits to protected branches. Every write operation:
- Creates a timestamped feature branch (
minh-update-YYYYMMDD-HHMMSS) - Ensures all file contents end with a trailing newline (POSIX convention)
- Commits changes to the branch
- Opens a merge request for human review
- Sets reviewers on the MR (if configured)
- Returns the MR URL for tracking
Key Components¶
| Component | Location | Role |
|---|---|---|
SafeGitLabWriter |
minh/src/integrations/safe_gitlab_writer.py |
Branch creation, commit, MR opening, reviewer assignment, trailing newline enforcement |
GitLabWriter |
minh/src/integrations/gitlab_writer.py |
Low-level GitLab API wrapper |
_ensure_trailing_newline |
minh/src/integrations/safe_gitlab_writer.py |
Utility that appends a newline to content missing one |
Trailing Newline Enforcement¶
All write paths (write_file, update_file, commit_batch_changes) now normalize content to end with at least one newline character before committing, following the POSIX convention. This is applied automatically — callers do not need to handle it.
For batch operations (commit_batch_changes), each change dict is shallow-copied before modification, so the caller's original data is never mutated.
# Internal helper used by all write methods
def _ensure_trailing_newline(content: str) -> str:
"""Ensure content ends with at least one newline (POSIX convention)."""
if content and not content.endswith("\n"):
return content + "\n"
return content
API¶
commit_batch_changes(project_id, changes, commit_message, reviewers=None)¶
Creates a single MR containing multiple file changes.
- project_id — GitLab project path (e.g.
the-smithy1/agents/knowledge-sanctuary) - changes — List of
{"action": "update|create", "file_path": ..., "content": ...}dicts - commit_message — Commit message for the branch
- reviewers — Optional list of GitLab usernames to set as MR reviewers
All content values in the changes list are automatically normalized to include a trailing newline. The original dicts are not mutated (shallow copies are used internally).
Returns {"success": True, "mr_url": ..., "commit_id": ..., "file_count": ...}.
GitLabWriter.set_mr_reviewers(project_id, mr_iid, reviewers)¶
Sets reviewers on an existing merge request by username.
- project_id — GitLab project path
- mr_iid — Merge request internal ID
- reviewers — List of GitLab usernames
Content Validation¶
Generated documentation content is validated before being committed. The validation layer (src/utils/metadata_utils.py) checks for several quality issues, including:
- Agent dialogue leakage — Detects conversational preamble or postamble that LLMs sometimes include instead of returning only the requested markdown. Matched patterns include:
"Here's the updated documentation:""I've updated/made/revised...""Would you like me to...""Let me know if...""Sure/Certainly/Of course,...""requires your permission/approval/confirmation"
Content that fails validation (e.g., contains agent dialogue) triggers regeneration rather than data loss.
Date Handling in Prompts¶
When generating or updating documentation, the system injects the actual date (YYYY-MM-DD format via date.today().isoformat()) directly into the user prompt rather than using vague references like "today's date". This ensures the LLM sets last_updated front matter fields to a concrete, deterministic value.
Related¶
See also¶
The portable technique in this document has been extracted into client-free patterns. This page keeps the implementation detail; the patterns carry the part that transfers.