{"id":49865161,"url":"https://github.com/cuttlefisch/or-east","last_synced_at":"2026-05-15T01:30:00.274Z","repository":{"id":132538446,"uuid":"583180229","full_name":"cuttlefisch/or-east","owner":"cuttlefisch","description":"Org Roam Extended Attribute Stat Tracking, OR-EAST","archived":false,"fork":false,"pushed_at":"2026-03-16T10:08:29.000Z","size":33,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-03-16T10:52:30.654Z","etag":null,"topics":["emacs-lisp","emacs-mode"],"latest_commit_sha":null,"homepage":"","language":"Emacs Lisp","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cuttlefisch.png","metadata":{"files":{"readme":"README.org","changelog":null,"contributing":"CONTRIBUTING.org","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2022-12-29T02:14:39.000Z","updated_at":"2026-03-16T10:08:33.000Z","dependencies_parsed_at":"2023-06-08T20:47:50.769Z","dependency_job_id":null,"html_url":"https://github.com/cuttlefisch/or-east","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/cuttlefisch/or-east","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cuttlefisch%2For-east","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cuttlefisch%2For-east/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cuttlefisch%2For-east/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cuttlefisch%2For-east/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cuttlefisch","download_url":"https://codeload.github.com/cuttlefisch/or-east/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cuttlefisch%2For-east/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33050012,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-13T13:14:54.681Z","status":"online","status_checked_at":"2026-05-14T02:00:06.663Z","response_time":57,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["emacs-lisp","emacs-mode"],"created_at":"2026-05-15T01:29:59.487Z","updated_at":"2026-05-15T01:30:00.252Z","avatar_url":"https://github.com/cuttlefisch.png","language":"Emacs Lisp","funding_links":[],"categories":[],"sub_categories":[],"readme":"#+TITLE: or-east\n\n#+HTML: \u003ca href=\"https://github.com/cuttlefisch/or-east/actions/workflows/ci.yml\"\u003e\u003cimg src=\"https://github.com/cuttlefisch/or-east/actions/workflows/ci.yml/badge.svg\" alt=\"CI\"\u003e\u003c/a\u003e\n#+HTML: \u003ca href=\"https://www.gnu.org/licenses/gpl-3.0\"\u003e\u003cimg src=\"https://img.shields.io/badge/License-GPLv3-blue.svg\" alt=\"License: GPL v3\"\u003e\u003c/a\u003e\n#+HTML: \u003ca href=\"https://www.gnu.org/software/emacs/\"\u003e\u003cimg src=\"https://img.shields.io/badge/Emacs-28.1%2B-purple.svg\" alt=\"Emacs 28.1+\"\u003e\u003c/a\u003e\n\n*Org Roam Extended Attribute Stat Tracking*\n\n=or-east= is an Emacs minor mode that automatically tracks usage statistics on\n[[https://github.com/org-roam/org-roam][org-roam]] nodes. It records timestamps in each node's property drawer whenever\nyou access, modify, or link to a node — no manual bookkeeping required.\n\n* Tracked Properties\n\n| Property        | Updated when                                         | Hook                                |\n|-----------------+------------------------------------------------------+-------------------------------------|\n| =last-accessed= | Node is opened via =org-roam-find-file=               | =org-roam-find-file-hook=            |\n| =last-modified= | Body content changes (detected via =buffer-hash=)     | =after-save-hook= (buffer-local)    |\n| =last-linked=   | Another node inserts a link to this node              | =org-roam-post-node-insert-hook=    |\n\n* How it works\n\nWhen =or-east-mode= is enabled, it installs three hooks:\n\n1. *Access tracking*: =org-roam-find-file-hook= runs\n   =or-east-node-update-access-time-by-id=, which sets =last-accessed= to the\n   current timestamp whenever you open a node.\n\n2. *Modification tracking*: The same hook also runs\n   =or-east--setup-modified-tracking=, which adds =or-east-node-update-stats= to\n   the buffer-local =after-save-hook=.  On each save, or-east computes a\n   =buffer-hash= of the file content from the =#+title= keyword onward and\n   compares it to a stored =hash= property.  If they differ, both =hash= and\n   =last-modified= are updated.  This means property-drawer-only changes (like\n   the timestamps themselves) do not trigger a modification.\n\n3. *Link tracking*: =org-roam-post-node-insert-hook= runs\n   =or-east-node-update-link-time-by-id= on the /target/ node whenever a link\n   is inserted from another node.\n\nAll saves performed by or-east use an inhibit flag to prevent recursive\n=after-save-hook= triggers.\n\n* Installation\n\n** straight.el / Doom Emacs\n\n#+begin_src elisp\n;; In packages.el (Doom)\n(package! or-east :recipe (:host github :repo \"cuttlefisch/or-east\"))\n\n;; In config.el\n(use-package! or-east-mode\n  :hook (org-roam-find-file . or-east-mode))\n#+end_src\n\n** use-package + straight\n\n#+begin_src elisp\n(use-package or-east-mode\n  :straight (:host github :repo \"cuttlefisch/or-east\")\n  :hook (org-roam-find-file . or-east-mode))\n#+end_src\n\n** Manual\n\nClone the repository, add it to your =load-path=, and require it:\n\n#+begin_src elisp\n(add-to-list 'load-path \"/path/to/or-east\")\n(require 'or-east-mode)\n(add-hook 'org-roam-find-file-hook #'or-east-mode)\n#+end_src\n\n* Usage\n\nOnce =or-east-mode= is active in an org-roam buffer, the three properties update\ntransparently during normal use. You can also call functions directly:\n\n- =or-east-enable= / =or-east-disable= — activate or deactivate the mode\n- =or-east-node-update-stats= — manually trigger a stat update (=M-x=)\n- =or-east-normalize-timestamps= — batch-rewrite all node timestamps to the current format\n\n* Configuration\n\n| Variable                                | Default | Description                        |\n|-----------------------------------------+---------+------------------------------------|\n| =or-east-node-stat-format-time-string=  | =\"%Y-%m-%d\"=  | Format string for timestamps (passed to =format-time-string=) |\n| =or-east-activity-weights=              | see below | Weights for each tracked property in the activity score |\n| =or-east-activity-decay-rate=           | =0.01=  | How quickly scores decay with age (higher = faster decay) |\n\nThe default format =\"%Y-%m-%d\"= produces ISO 8601 dates like =2026-03-21=.\nChange it to suit your preference:\n\n#+begin_src elisp\n(setq or-east-node-stat-format-time-string \"%Y-%m-%d %H:%M\")\n#+end_src\n\n* Activity-based search prioritization\n\n=or-east= can sort =org-roam-node-find= results by activity, so recently\nmodified/accessed/linked nodes appear first. Each tracked property\ncontributes a weighted, time-decayed score:\n\n#+begin_src elisp\n;; Default weights — modify contributes most, linking least\n(setq or-east-activity-weights\n  '((last-accessed . 1.0)\n    (last-modified . 2.0)\n    (last-linked   . 0.5)))\n\n;; Decay rate controls how fast old activity fades\n;; 0.01 = gradual (50% at ~100 days), 0.05 = aggressive (50% at ~20 days)\n(setq or-east-activity-decay-rate 0.01)\n#+end_src\n\nTo enable activity sorting as the default for =org-roam-node-find=:\n\n#+begin_src elisp\n(setq org-roam-node-default-sort 'activity)\n#+end_src\n\nThis works because =or-east= registers =org-roam-node-read-sort-by-activity=\nfollowing org-roam's naming convention. You can also pass the sort\nfunction directly:\n\n#+begin_src elisp\n(org-roam-node-find nil nil #'or-east-node-sort-by-activity)\n#+end_src\n\n** Freshness-weighted search\n\nUse activity sorting as a tiebreaker so that equally-matched search results\nare ranked by recency:\n\n#+begin_src elisp\n;; Make org-roam-node-find default to activity-based ordering\n(setq org-roam-node-default-sort 'activity)\n#+end_src\n\nWith this setting, when you type a query that matches several nodes equally\nwell, the ones you've touched most recently float to the top.\n\n** Custom weight profiles\n\nTailor the weights to your workflow.  For example, a research-heavy config\nthat prioritizes discovery through links:\n\n#+begin_src elisp\n;; Research mode: heavily weight links for discovery\n(setq or-east-activity-weights\n  '((last-accessed . 0.5)\n    (last-modified . 1.0)\n    (last-linked   . 3.0)))\n#+end_src\n\nOr a daily-driver config that favors nodes you open frequently:\n\n#+begin_src elisp\n;; Daily driver: favor recently accessed nodes\n(setq or-east-activity-weights\n  '((last-accessed . 3.0)\n    (last-modified . 1.0)\n    (last-linked   . 0.5)))\n#+end_src\n\n** Agenda/dashboard integration\n\nQuery nodes by activity score for a \"recently active nodes\" dashboard:\n\n#+begin_src elisp\n(defun my/or-east-top-nodes (\u0026optional n)\n  \"Return the top N most active org-roam nodes (default 10).\"\n  (let* ((n (or n 10))\n         (nodes (org-roam-node-list))\n         (scored (sort nodes\n                       (lambda (a b)\n                         (\u003e (or-east-node-activity-score a)\n                            (or-east-node-activity-score b))))))\n    (seq-take scored n)))\n\n;; Example: print titles of your 5 most active nodes\n(dolist (node (my/or-east-top-nodes 5))\n  (message \"%s (score: %.2f)\"\n           (org-roam-node-title node)\n           (or-east-node-activity-score node)))\n#+end_src\n\n* Development\n\n#+begin_src shell\ncask install\nmake test\n#+end_src\n\nSee [[file:CONTRIBUTING.org][CONTRIBUTING.org]] for full development guidelines.\n\n* Changelog\n\nSee [[file:CHANGELOG.org][CHANGELOG.org]] for a list of notable changes.\n\n* License\n\n[[file:LICENSE][GNU General Public License v3.0]]\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcuttlefisch%2For-east","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcuttlefisch%2For-east","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcuttlefisch%2For-east/lists"}