Skip to content

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:

  1. Creates a timestamped feature branch (minh-update-YYYYMMDD-HHMMSS)
  2. Ensures all file contents end with a trailing newline (POSIX convention)
  3. Commits changes to the branch
  4. Opens a merge request for human review
  5. Sets reviewers on the MR (if configured)
  6. 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.

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.