gsantner/markor
Text editor - Notes & ToDo (for Android) - Markdown, todo.txt, plaintext, math, ..
Mixed signals — read the receipts
weakest axisnon-standard license (Other); no tests detected
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ✓Last commit 3w ago
- ✓14 active contributors
- ✓Other licensed
Show all 7 evidence items →Show less
- ✓CI configured
- ⚠Concentrated ownership — top contributor handles 64% of recent commits
- ⚠Non-standard license (Other) — review terms
- ⚠No test directory detected
What would change the summary?
- →Use as dependency Concerns → Mixed if: clarify license terms
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Forkable" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/gsantner/markor)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/gsantner/markor on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: gsantner/markor
Generated by RepoPilot · 2026-05-09 · Source
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/gsantner/markor shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
🎯Verdict
WAIT — Mixed signals — read the receipts
- Last commit 3w ago
- 14 active contributors
- Other licensed
- CI configured
- ⚠ Concentrated ownership — top contributor handles 64% of recent commits
- ⚠ Non-standard license (Other) — review terms
- ⚠ No test directory detected
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live gsantner/markor
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/gsantner/markor.
What it runs against: a local clone of gsantner/markor — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in gsantner/markor | Confirms the artifact applies here, not a fork |
| 2 | License is still Other | Catches relicense before you depend on it |
| 3 | Default branch master exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 50 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of gsantner/markor. If you don't
# have one yet, run these first:
#
# git clone https://github.com/gsantner/markor.git
# cd markor
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of gsantner/markor and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "gsantner/markor(\\.git)?\\b" \\
&& ok "origin remote is gsantner/markor" \\
|| miss "origin remote is not gsantner/markor (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(Other)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"Other\"" package.json 2>/dev/null) \\
&& ok "license is Other" \\
|| miss "license drift — was Other at generation time"
# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
&& ok "default branch master exists" \\
|| miss "default branch master no longer exists"
# 4. Critical files exist
test -f "app/src/main/java/net/gsantner/markor/activity/DocumentActivity.java" \\
&& ok "app/src/main/java/net/gsantner/markor/activity/DocumentActivity.java" \\
|| miss "missing critical file: app/src/main/java/net/gsantner/markor/activity/DocumentActivity.java"
test -f "app/src/main/java/net/gsantner/markor/activity/DocumentEditAndViewFragment.java" \\
&& ok "app/src/main/java/net/gsantner/markor/activity/DocumentEditAndViewFragment.java" \\
|| miss "missing critical file: app/src/main/java/net/gsantner/markor/activity/DocumentEditAndViewFragment.java"
test -f "app/src/main/java/net/gsantner/markor/format/FormatRegistry.java" \\
&& ok "app/src/main/java/net/gsantner/markor/format/FormatRegistry.java" \\
|| miss "missing critical file: app/src/main/java/net/gsantner/markor/format/FormatRegistry.java"
test -f "app/src/main/java/net/gsantner/markor/format/TextConverterBase.java" \\
&& ok "app/src/main/java/net/gsantner/markor/format/TextConverterBase.java" \\
|| miss "missing critical file: app/src/main/java/net/gsantner/markor/format/TextConverterBase.java"
test -f "app/build.gradle" \\
&& ok "app/build.gradle" \\
|| miss "missing critical file: app/build.gradle"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 50 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~20d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/gsantner/markor"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
⚡TL;DR
Markor is a lightweight Android text editor that supports multiple markup formats (Markdown, todo.txt, Zim/WikiText, plaintext, CSV, YAML, JSON, etc.) for creating notes, managing to-do lists, and working with documents entirely offline. It compiles to a single APK (~1.5MB Java codebase) with syntax highlighting, HTML/PDF preview and export, and full filesystem integration via a notebook folder model. Monolithic Android app structure: app/src/main/ contains the core editor logic and assets (highlight/, templates/, img/). Product flavors split testing (flavorAtest with IS_TEST_BUILD=true) from production (flavorGplay, flavorDefault). Assets include highlight.js language definitions (cpp.json, java.json, python.json), themes, and template documents. Makefile provides build automation alongside Gradle.
👥Who it's for
Android users who want a simple, privacy-respecting note-taking and task management app without cloud sync or ads; developers and power users who prefer interoperable plaintext formats (Markdown, todo.txt) and want to avoid vendor lock-in. Also targets contributors who want to build features around text markup processing on mobile.
🌱Maturity & risk
Production-ready and actively maintained. The project has 163+ version releases, sustained commits through 2025 (led by gsantner), CI/CD via GitHub Actions (build-android-project.yml), and is available on F-Droid and GitHub releases. Community discussion and translation infrastructure (Crowdin) are established, indicating stable active development without abandonment risk.
Low risk for a mature Android app. Single primary maintainer (gsantner) is a potential concern for long-term continuity, but the codebase is straightforward Java without heavy third-party dependency chains (flexmark-java 0.42.14 is the main markup engine). No obvious red flags in open issues visible; ProGuard rules (proguard-rules.pro) indicate production obfuscation is configured. Oldest visible commit is from 2017, demonstrating sustained stability.
Active areas of work
Active bug fixes and feature polish leading to v2.16.1 (versionCode 163). GitHub Actions CI is running on commits. Dependabot is configured (.github/dependabot.yml) for automated dependency updates. Community issues and pull requests are actively triaged via issue templates (BUG_REPORT.yml, FEATURE_REQUEST.yml). Recent work appears focused on editor stability and format support expansion.
🚀Get running
Clone and build: git clone https://github.com/gsantner/markor && cd markor && make (Makefile present) or use Android Studio with ./gradlew build. For emulator/device testing: ./gradlew installDebug. Minimum SDK is 18 (Android 4.3+); target is current SDK (see build.gradle). No external services required—everything is local.
Daily commands:
Development: ./gradlew assembleDebug builds debug APK to app/build/outputs/apk/. Use ./gradlew installDebug to deploy to connected device/emulator. Makefile targets (if present) may wrap these—check make help. For IDE: open in Android Studio, select flavorDefault or flavorAtest variant, and run via Gradle panel.
🗺️Map of the codebase
app/src/main/java/net/gsantner/markor/activity/DocumentActivity.java— Main activity entry point for document editing; all document workflows flow through here and understanding its lifecycle is essential for any UI feature workapp/src/main/java/net/gsantner/markor/activity/DocumentEditAndViewFragment.java— Core fragment managing the editor/viewer UI with syntax highlighting and markdown rendering; critical for understanding the text editing pipelineapp/src/main/java/net/gsantner/markor/format/FormatRegistry.java— Registry pattern managing all supported formats (Markdown, Asciidoc, CSV, todo.txt); extension point for adding new document typesapp/src/main/java/net/gsantner/markor/format/TextConverterBase.java— Abstract base class for all format converters; defines the interface that every format implementation must followapp/build.gradle— Build configuration including Flexmark dependency (v0.42.14 for Markdown processing), SDK versions, and flavor definitionsapp/src/main/AndroidManifest.xml— App manifest declaring all activities, permissions, and content providers; required reading for understanding the app's capabilities and entry pointsapp/src/main/java/net/gsantner/markor/ApplicationObject.java— Application singleton managing global state, preferences, and initialization; dependency injection point for core services
🛠️How to make changes
Add a New Markup Format
- Create a new format directory under app/src/main/java/net/gsantner/markor/format/{format} (e.g., format/rst) (
app/src/main/java/net/gsantner/markor/format) - Implement TextConverterBase subclass (e.g., RstTextConverter.java) to handle HTML preview conversion (
app/src/main/java/net/gsantner/markor/format/TextConverterBase.java) - Implement ActionButtonBase subclass (e.g., RstActionButtons.java) with format-specific toolbar actions (
app/src/main/java/net/gsantner/markor/format/ActionButtonBase.java) - Create a SyntaxHighlighter subclass for custom text styling (e.g., RstSyntaxHighlighter.java), or reference existing JSON rules in app/src/main/assets/highlight/languages/ (
app/src/main/assets/highlight/languages/map.properties) - Register the format in FormatRegistry.java by adding a mapping from file extensions to your new converter class (
app/src/main/java/net/gsantner/markor/format/FormatRegistry.java) - Add a template file in app/src/main/assets/templates/ (e.g., rst-reference.rst) for user reference (
app/src/main/assets/templates)
Add a New Quick Action Button to the Toolbar
- Identify the format-specific ActionButtons class (e.g., MarkdownActionButtons.java for Markdown) (
app/src/main/java/net/gsantner/markor/format/markdown/MarkdownActionButtons.java) - Add a new method in the ActionButtons subclass that creates an ActionItem with icon, label, and insertion text/replacement logic (
app/src/main/java/net/gsantner/markor/format/ActionButtonBase.java) - Register the new button in the getButtons() or getActionButtons() method by appending it to the returned list (
app/src/main/java/net/gsantner/markor/format/markdown/MarkdownActionButtons.java) - Test by opening DocumentEditAndViewFragment.java and verifying the button appears in the toolbar when editing that format
🪤Traps & gotchas
No explicit test directory visible in the file listing—tests may be minimal or under app/src/test/ (not shown). Build requires Android SDK and recent Gradle; older minSdkVersion=18 suggests broad device support but may limit some modern APIs. Product flavors (flavorAtest, flavorGplay, flavorDefault) have different applicationId and version codes—ensure correct flavor selected during development. Markdown rendering depends on flexmark 0.42.14 (relatively old, 0.62.2 is current); upgrading may introduce breaking changes in syntax handling.
💡Concepts to learn
- Markdown Abstract Syntax Tree (AST) parsing — Markor uses flexmark-java to parse Markdown into an AST for syntax highlighting, preview, and export; understanding AST traversal is critical for adding custom markup rules or output formats.
- Android product flavors (build variants) — Markor uses flavorAtest, flavorGplay, and flavorDefault to ship different binaries (test, Google Play, F-Droid) with different app IDs and version codes; essential for understanding multi-channel release strategy.
- ProGuard/R8 code obfuscation — app/proguard-rules.pro configures which classes are kept/stripped in release builds; necessary to understand if reflection-based features (like plugin loading) are broken by obfuscation.
- todo.txt format specification — Markor natively supports todo.txt files alongside Markdown; understanding the syntax (priorities, dates, tags) is needed to implement format-specific features like task filtering or date parsing.
- Syntax highlighting tokenization — Markor's highlight/languages/*.json files define lexical rules for syntax coloring; understanding tokenization patterns is needed to add new language support or customize existing highlighting.
- Android FileProvider and scoped storage — Markor reads/writes user documents to arbitrary filesystem folders (Notebook); understanding Android 10+ scoped storage restrictions is critical for file I/O features and permissions.
- minSdkVersion backwards compatibility — Markor targets minSdk=18 (Android 4.3, 2013) for broad device support; this constrains available APIs and requires compatibility library imports, affecting modern feature adoption.
🔗Related repos
jotterpad/jotterpad— Direct competitor: Android Markdown note editor with similar offline-first, plaintext-interoperable design; useful for feature comparison and UX patterns.vsch/flexmark-java— Core dependency: Markor uses flexmark-java 0.42.14 for Markdown parsing; essential to understand for custom syntax extensions or format support.fsnotify/system_fonts— Potential typography dependency: if Markor needs custom font rendering, this project provides a cross-platform font discovery abstraction.gsantner/writeily-pro— Predecessor/spiritual sibling: also by gsantner, an older note-taking app; useful reference for design decisions and deprecated patterns to avoid.ampere/plain-text-todo— Related ecosystem: minimal todo.txt editor that complements Markor's task management; useful for understanding todo.txt spec and user workflows.
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add unit tests for markdown parsing and rendering in flexmark integration
The repo uses flexmark-java (v0.42.14) for markdown parsing but there are no visible unit tests in the file structure for testing markdown parsing, rendering edge cases, or format conversions. This is critical for a markdown editor to ensure correctness across different markdown dialects and extensions.
- [ ] Create app/src/test/java/net/gsantner/markor/format/ directory
- [ ] Add tests for markdown parsing with flexmark (test headers, lists, code blocks, inline formatting)
- [ ] Add tests for todo.txt format parsing and validation
- [ ] Add tests for conversion between supported formats (markdown, todo.txt, plaintext)
Create GitHub Actions workflow for Android instrumented tests on emulator
The repo has build-android-project.yml for building, but no visible workflow for running instrumented/UI tests on Android emulator. This would catch runtime issues across different Android API levels (minSdk 18 through latest) that static analysis misses. Critical for a mobile app handling user-facing features.
- [ ] Add .github/workflows/android-instrumented-tests.yml workflow file
- [ ] Configure emulator setup for API levels 21, 28, and 33+
- [ ] Add test execution for all product flavors (flavorAtest, flavorDefault, flavorGplay)
- [ ] Add JUnit test discovery and reporting to workflow
Document file format specifications and parsing rules in app/src/main/java/net/gsantner/markor/format/
The assets directory contains reference files (markor-markdown-reference.md, orgmode-reference.org, etc.) but there's no corresponding developer documentation explaining how each format is parsed, what extensions are supported, or what the parsing limitations are. This would help new contributors understand the format handling code.
- [ ] Create docs/FORMAT_SPECIFICATIONS.md documenting supported markdown extensions
- [ ] Add docs/TODO_TXT_PARSING.md with parsing rules and edge cases for todo.txt
- [ ] Document org-mode, asciidoc, and zim-wiki support status and limitations
- [ ] Link format specs from relevant Java source files in app/src/main/java/net/gsantner/markor/format/
🌿Good first issues
- Add unit tests for flexmark-java integration: app/src/test/java/net/gsantner/markor/MarkupParsingTest.java is likely missing. Start by testing rendering of basic Markdown, todo.txt, and YAML to catch regressions.
- Implement dark theme toggle for highlight themes: currently highlight/themes/default.json exists but no light alternate; add highlight/themes/dark.json and wire theme selection in app settings.
- Document the template system: create docs/TEMPLATES.md explaining how users can add custom templates to app/src/main/assets/templates/, then add a 'Create from template' UI feature.
⭐Top contributors
Click to expand
Top contributors
- @gsantner — 64 commits
- @harshad1 — 11 commits
- @guanglinn — 8 commits
- @JSchmerling — 6 commits
- @xn-7492 — 2 commits
📝Recent commits
Click to expand
Recent commits
81d040a— Add Markor settings shortcut to Android system settings, by @gsantner (gsantner)e6edfb5— Allow starting on TV device, by @gsantner (gsantner)f33eb6a— Markor v2.16.1 (code 163) (gsantner)e7dc78b— fix: stabilize editor layout sizing to prevent large-file open slowdown (PR #2769, closes #2739 #2652 #2716) (gsantner)e48b574— Update translations (PR #2758) (gsantner)ec4ca0e— v2.16.0: text area behind bar (at least in todo.txt), rudimentary fix #2757 by @gsantner (gsantner)24dc586— Fix unable to open links in custom tabs, falling back to the browser instead (PR #2764) (xn-7492)a3c8a3c— Partially revert WebView: disable file access - commit c25fc505e080d90dea8a3171f0849e3ce55f3bfc, closes #2759 (gsantner)4cf0218— Markor v2.16.0 (code 162) (gsantner)4cf4fe1— AsciiDoc: Fix cursor being hidden; Copy links in view-mode by long press (PR #2730) (guanglinn)
🔒Security observations
The Markor codebase shows moderate security maturity with some areas of concern. The most critical issue is the use of a significantly outdated dependency (flexmark-java 0.42.14 from 2018), which requires immediate updating. The minimum SDK version of 18 (Android 4.3) is outdated and should be raised to leverage modern security features. The incomplete build.gradle configuration requires review and completion. Overall, the project would benefit from: (1) updating all dependencies to current versions, (2) raising minimum SDK requirements, (3) completing the build configuration, and (4) implementing stricter controls around test vs. production builds. No hardcoded secrets, obvious injection vulnerabilities, or Docker misconfigurations were detected in the provided files.
- High · Outdated Flexmark-Java Library —
app/build.gradle (ext.version_library_flexmark = "0.42.14"). The project uses flexmark-java version 0.42.14, which was released in 2018 and is significantly outdated. This version likely contains known security vulnerabilities and lacks security patches available in newer versions. The library is used for Markdown parsing, which could be an attack vector for various injection attacks. Fix: Update to the latest stable version of flexmark-java. Check the GitHub releases page for the project and upgrade to at least version 0.62.0 or later. Review release notes for breaking changes and test thoroughly after upgrading. - Medium · Incomplete Build Gradle Configuration —
app/build.gradle. The build.gradle file appears to be truncated with an incomplete flavor definition ('flavorGplay' section ends abruptly with just 'f'). This suggests incomplete or corrupted configuration that could lead to unexpected build behavior or missing security-related configurations. Fix: Review and complete the build.gradle configuration. Ensure all product flavors are properly defined with appropriate security settings for each variant. - Medium · Minimum SDK Version Too Low —
app/build.gradle (rootProject.ext.version_minSdk = 18). The project targets Android API level 18 (minSdkVersion) as the minimum supported version. Android 4.3 (API 18) was released in 2013 and lacks modern security features. This exposes the app to known vulnerabilities in older Android versions and limits the security features available to the application. Fix: Consider raising the minimum SDK version to at least API 21 (Android 5.0) or higher. Modern best practices recommend API 24+ (Android 7.0). This enables access to newer security APIs and reduces the attack surface. - Low · Build Metadata Exposure —
app/build.gradle (buildConfigField entries for GITHASH, GITMSG, BUILD_DATE). The build.gradle includes Git-related build fields (GITHASH, GITMSG) and build dates that are embedded in the APK. While not directly a security vulnerability, exposing Git commit information could provide reconnaissance information to attackers about the codebase. Fix: Consider whether Git commit information needs to be exposed in production builds. For release builds, consider conditionally excluding this metadata or restricting it to debug builds only using BuildConfig.DEBUG checks. - Low · Test Build Configuration in Source Control —
app/build.gradle (flavorAtest configuration). The build.gradle defines multiple product flavors including a test build flavor (flavorAtest) with dynamic version codes based on current date. While this is a development convenience, it suggests test builds may be released, and the versioning scheme could cause confusion in production. Fix: Ensure that test/debug builds are never distributed to end users. Implement CI/CD guardrails to prevent test builds from being published. Use build variants to completely separate debug and release configurations.
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.