{"id":24609670,"url":"https://github.com/turbopape/milestones","last_synced_at":"2025-12-12T01:15:09.435Z","repository":{"id":21755550,"uuid":"25077534","full_name":"turbopape/milestones","owner":"turbopape","description":"The Automagic Project Planner","archived":false,"fork":false,"pushed_at":"2021-12-12T20:29:44.000Z","size":184,"stargazers_count":118,"open_issues_count":1,"forks_count":21,"subscribers_count":6,"default_branch":"master","last_synced_at":"2024-11-28T14:18:00.587Z","etag":null,"topics":["artificial-intelligence","clojure","project-planning"],"latest_commit_sha":null,"homepage":"","language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/turbopape.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-10-11T12:36:07.000Z","updated_at":"2024-05-31T07:46:05.000Z","dependencies_parsed_at":"2022-09-05T03:50:29.640Z","dependency_job_id":null,"html_url":"https://github.com/turbopape/milestones","commit_stats":null,"previous_names":["automagictools/milestones"],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/turbopape%2Fmilestones","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/turbopape%2Fmilestones/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/turbopape%2Fmilestones/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/turbopape%2Fmilestones/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/turbopape","download_url":"https://codeload.github.com/turbopape/milestones/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":235481663,"owners_count":18997124,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["artificial-intelligence","clojure","project-planning"],"created_at":"2025-01-24T18:16:31.824Z","updated_at":"2025-12-12T01:15:09.400Z","avatar_url":"https://github.com/turbopape.png","language":"Clojure","funding_links":[],"categories":["Project Management"],"sub_categories":[],"readme":"Milestones - The Automagic Project Planner\n=============================================\n\n[![License MIT](https://img.shields.io/badge/License-MIT-blue.svg)](http://opensource.org/licenses/MIT)\n[![Build Status](https://travis-ci.org/turbopape/milestones.svg?branch=master)](https://travis-ci.org/turbopape/milestones)\n[![Clojars Project](https://img.shields.io/clojars/v/org.clojars.turbopape/milestones.svg)](https://clojars.org/org.clojars.turbopape/milestones)\n[![#milestones on slack channel](https://img.shields.io/badge/chat-%23%20team-yellowgreen.svg)](https://automagic-tools.slack.com/signup)\n\n\u003cimg src=\"./logo.jpg\"\n alt=\"Automagic logo\" title=\"The Robot and the Bunny\" align=\"right\" /\u003e\n\n\u003e \"Any sufficiently advanced technology is indistinguishable from magic\"\n- According to Clarke's 3rd Law\n\n\nMilestones is a Clojure and ClojureScript library that needs only your project's task description in order to generate the best possible schedule for you. This is based on the priorities of the tasks that you have set (in terms of fields in tasks, more about this in a second).\n\nConstraints on tasks are:\n- Resources (i.e, which resource is needed to perform a particular task),\n- The task's duration\n- Predecessors (i.e, which tasks need to be done before a particular task can be fired).\n\nBased on the above constraints, Milestones either generates\nthe schedule (if it does not detect scheduling errors) or shows you any kind\nof error it may have found.\n\nTasks are basically build up out of a map containing IDs as keys and information about\nthe tasks as values. Information about a task is itself a map of\nassociating fields to values; here is an example:\n\n```Clojure\n{ 1 { :task-name \"A description about this task\"\n      :resource-id 2\n      :duration 5 :priority 1}\n\n  2 {:task-name \"A description about this task\"\n      :resource-id 1\n      :duration 4\n      :priority 1\n      :predecessors [1]} }\n```\n\nMilestones tries to detect any circular dependencies (tasks\nthat depend on themselves or tasks that end up depending on\nthemselves). The task's definition must be a directed\nnon-cyclical graph.\n\nTasks (that are not milestones) without a resource-id won't be scheduled and will be reported as erroneous.\n\n\nSpecial tasks with `:is-milestone \"whatever\"` are milestones. They are assigned a random user\nand a duration 1, so they can enter the computation like ordinary tasks.\nThey must have predecessors, otherwise they will be reported as erroneous.\n\nIf nothing went wrong during the generation process, the output of Milestones is a schedule. It will be\ncomprised of the very same tasks mapped with a `:begin` field, telling us when to begin each task.\nThe time for each task is represented as an integer value.\n\n\n```Clojure\n{ 1 { :task-name \"A description about this task\"\n      :resource-id 2\n      :duration 5\n      :priority 1\n      :begin 0}\n\n  2 {:task-name \"A description about this task\"\n     :resource-id 1\n     :duration 4\n     :priority 1\n     :predecessors [1] :begin 5} }\n```\n\n\n## See Milestones OnLine\n\nYou can see Milestones in\naction [here.](http://turbopape.github.io/milestones). We\nuse\n[Google Charts Lib](https://developers.google.com/chart/interactive/docs/gallery/ganttchart) to\ndraw GANTT Charts, and in some-way we rely on this library time\nresolution mechanisms to be able to mix different time units for\ndifferent tasks. Actually, tasks on web can have time units, and you\ncan get a real schdule based on duration expressed in actual time\nunits!  Currently, the web interface schedules tasks starting from\ntoday.\nAlso, Priority and predecessors are optional in the web\ninterface. This is related to the natural language implementation, but\nroughly speaking this means that if you omit these clauses in your\ntask descriptions, the system will forgive you.\n\nThe Web version is being lifted to use the newly developed NLP\nlibrary: [postagga](https://github.com/turbopape/postagga). Now\nmilestones will host the scheduling library, the NLP facilities etc\nhas moved to this new project.\n\n## Installation\n\nYou can grab Milestones from clojars. Using Leiningen, you put the dependency in the **:dependencies** section in your project.clj:\n\n[![Clojars Project](https://img.shields.io/clojars/v/org.clojars.turbopape/milestones.svg)](https://clojars.org/org.clojars.turbopape/milestones)\n\n## Usage\n\nStart the library using the **schedule** function.\nPass a map to it containing tasks and a vector containing the\nproperties that define how the scheduler will prioritize the tasks.\nPriorities at the left are considered first. The lower the number, the earlier it is scheduled.\nSay you want to schedule tasks with lower `:priority` and then lower `:duration`, first do:\n\n```Clojure\n    (schedule tasks [:priority :duration])\n```\n\nIt returns tasks with **`:begin`** fields, or an error\n\n```Clojure\n    {:errors nil\n\n    :result {1 {**:begin** }}}\n```\n\nOr:\n\n```Clojure\n    {:errors {:reordering-errors reordering-errors\n             :tasks-w-predecessors-errors tasks-predecessors-errors\n             :tasks-cycles tasks-cycles\n             :milestones-w-no-predecessors milestones-w-no-predecessors}\n\n     :result nil}\n```\n\n### Sample Case\n\nFor example, if you have tasks defined to:\n\n```Clojure\n    {\n    1 {:task-name \"Bring bread\"\n         :resource-id \"mehdi\"\n         :duration 5\n         :priority 1\n         :predecessors []}\n\n    2 {:task-name \"Bring butter\"\n       :resource-id \"rafik\"\n       :duration 5\n       :priority 1\n       :predecessors []}\n\n    3 {:task-name \"Put butter on bread\"\n       :resource-id \"salma\"\n       :duration 3\n       :priority 1\n       :predecessors [1 2]}\n\n    4 {:task-name \"Eat toast\"\n       :resource-id \"rafik\"\n        :duration 4\n        :priority 1\n        :predecessors [3]}\n\n    5 {:task-name \"Eat toast\"\n        :resource-id \"salma\"\n        :duration 4\n        :priority 1\n        :predecessors [3]}\n\n    ;; now some milestones\n    6 {:task-name \"Toasts ready\"\n        :is-milestone true\n        :predecessors [3]}}\n```\nyou would want to run\n\n```Clojure\n    (schedule tasks [:duration])\n```\n\nand you'd have:\n\n```Clojure\n     {:error nil,\n      :result {\n      ;;tasks with :begin field, i.e at what time shall they be fired.\n      1\n      {:achieved 5,\n       :begin 1,\n       :task-name \"Bring bread\",\n       :resource-id \"mehdi\",\n       :duration 5,\n       :priority 1,\n       :predecessors []},\n      2\n      {:achieved 5,\n       :begin 1,\n       :task-name \"Bring butter\",\n       :resource-id \"rafik\",\n       :duration 5,\n       :priority 1,\n       :predecessors []},\n      3\n      {:resource-id \"salma\",\n       :achieved 3,\n       :duration 3,\n       :predecessors [1 2],\n       :begin 6,\n       :task-name \"Put butter on bread\",\n       :priority 1},\n      4\n      {:resource-id \"rafik\",\n       :achieved 4,\n       :duration 4,\n       :predecessors [3],\n       :begin 9,\n       :task-name \"Eat toast\",\n       :priority 1},\n      5\n      {:resource-id \"salma\",\n       :achieved 4,\n       :duration 4,\n       :predecessors [3],\n       :begin 9,\n       :task-name \"Eat toast\",\n       :priority 1},\n      6\n      {:achieved 1,\n       :duration 1,\n       :predecessors [3],\n       :begin 9,\n       :task-name \"Toasts ready\",\n       :is-milestone true}}}\n```\n\nYou can then pass this to another program to render as a Gantt chart (ours is coming soon).\nYou should have `:achieved` equal to `:duration`, or Milestones will not be able to schedule all of the tasks (this\nshould not happen).\n\n### Errors\n\n Error Map Key                 |  What it means\n-------------------------------|-----------------------------\n:unable-to-schedule            | Something made it impossible for the recursive algorithm to terminate...\n:reordering-errors             | { 1 [:priority],...} You gave priority to tasks according to fields (:priority) which some tasks (1) lack).\n:tasks-w-predecessors-errors   | :{6 [13],...} These tasks have these non-existent predecessors.\n:tasks-w-no-resources          | [1,... These tasks are not milestones and are not assigned to any resource.\n:tasks-cycles                  | [[1 2 3]... Set of tasks that are in a cycle. In this example, 2 depends on 1, 2 on 3 and 3 on 1.\n:milestones-w-no-predecessors  | [1 2...  These milestones don't have predecessors.\n\n## History\n\nThe concept of auto-magic project scheduling is inspired from **the great**\n[Taskjuggler.](http://www.taskjuggler.org).\n\nThe first prototype of Milestones was built as an entry to the Clojure\nCup 2014. You can find the code and some technical explanation of the\nalgorithms in use (core.async, etc...)\n[here.](https://github.com/turbopape/milestones-clojurecup2014)\n\nas of version 0.2.X and above, milestone uses a purely functional\nalgorithm using the same logic of assigning work units, but simply\nrelying on recur to advance the system status.\n\nAlthough the prototype showcases the main idea, this repository is the official one, i.e, contains latest versions and is more thoroughly tested.\n\n## Code Of Conduct\nPlease note that this project is released with a [Contributor Code of Conduct](./CODE_OF_CONDUCT.md). By participating in this project you agree to abide by its terms.\n\n## License and Credits\n\nCopyright © 2016 Rafik Naccache and [Contributors](./CONTRIBUTORS.md). Distributed under the terms of the [MIT License](https://github.com/turbopape/milestones/blob/master/LICENSE).\n\nAll Libraries used in this project (see project.clj) are owned by their respective authors and their respective licenses apply.\n\nThe Logo is created by my talented friend the great [Chakib Daoud](https://www.facebook.com/3amettaher/?fref=ts)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fturbopape%2Fmilestones","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fturbopape%2Fmilestones","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fturbopape%2Fmilestones/lists"}